USER
// 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_PUSH_EAX() {
push(regs.EAX);
}
void Emulator::instr_PUSH_ECX() {
push(regs.ECX);
}
void Emulator::instr_PUSH_EDX() {
push(regs.EDX);
}
void Emulator::instr_PUSH_EBX() {
push(regs.EBX);
}
void Emulator::instr_PUSH_ESP() {
push(regs.ESP);
}
void Emulator::instr_PUSH_EBP() {
push(regs.EBP);
}
void Emulator::instr_PUSH_ESI() {
push(regs.ESI);
}
void Emulator::instr_PUSH_EDI() {
push(regs.EDI);
}
void Emulator::instr_CLD() {
// Clear the Direction Flag (DF), which is bit 10 in EFLAGS
regs.EFLAGS &= ~DF;
// Optionally, print debug information
std::cout << "Выполнена инструкция CLD (Direction Flag сброшен).\n";
}
void Emulator::instr_PUSH_imm8() {
int8_t imm8 = static_cast<int8_t>(fetch_byte()); // Получаем 8-битное значение
push(static_cast<uint32_t>(imm8)); // Преобразуем в 32-битное знаковое значение и помещаем в стек
}
void Emulator::push(uint32_t value) {
if (regs.ESP < 4) {
std::cerr << "Stack overflow при попытке записать в стек.\n";
error_flag = true;
running = false;
return;
}
regs.ESP -= 4; // Уменьшаем указатель стека
write_memory_dword(regs.ESP, value); // Записываем значение в стек
}
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_POP_ESP() {
if (regs.ESP + 4 > memory.size()) {
std::cerr << "Stack underflow on POP ESP.\n";
error_flag = true;
running = false;
return;
}
regs.ESP = read_memory_dword(regs.ESP);
regs.ESP += 4;
}
void Emulator::instr_POP_EBX() {
if (regs.ESP + 4 > memory.size()) {
std::cerr << "Stack underflow on POP EBX.\n";
error_flag = true;
running = false;
return;
}
regs.EBX = read_memory_dword(regs.ESP);
regs.ESP += 4;
}
void Emulator::instr_POP_EDX() {
if (regs.ESP + 4 > memory.size()) {
std::cerr << "Stack underflow on POP EDX.\n";
error_flag = true;
running = false;
return;
}
regs.EDX = read_memory_dword(regs.ESP);
regs.ESP += 4;
}
void Emulator::instr_POP_ECX() {
if (regs.ESP + 4 > memory.size()) {
std::cerr << "Stack underflow on POP ECX.\n";
error_flag = true;
running = false;
return;
}
regs.ECX = read_memory_dword(regs.ESP);
regs.ESP += 4;
}
void Emulator::instr_POP_EAX() {
if (regs.ESP + 4 > memory.size()) {
std::cerr << "Stack underflow on POP EAX.\n";
error_flag = true;
running = false;
return;
}
regs.EAX = read_memory_dword(regs.ESP);
regs.ESP += 4;
}
void Emulator::instr_POP_ESI() {
if (regs.ESP + 4 > memory.size()) {
std::cerr << "Stack underflow on POP ESI.\n";
error_flag = true;
running = false;
return;
}
// Считываем значение со стека и сохраняем его в регистр ESI
regs.ESI = read_memory_dword(regs.ESP);
regs.ESP += 4; // Увеличиваем указатель стека
std::cout << "Выполнен POP ESI. Значение в регистре ESI: " << std::hex << regs.ESI << "\n";
}
void Emulator::instr_POP_EDI() {
if (regs.ESP + 4 > memory.size()) {
std::cerr << "Stack underflow on POP EDI.\n";
error_flag = true;
running = false;
return;
}
regs.EDI = read_memory_dword(regs.ESP);
regs.ESP += 4;
}
void Emulator::instr_MOV_Ev_Iv() {
uint8_t modrm = fetch_byte();
Operand operand = decode_operand(modrm);
uint32_t immediate = fetch_dword();
if (operand.is_memory) {
write_memory_dword(operand.address, immediate);
} else {
uint32_t* reg = get_register_by_code(operand.register_code);
if (!reg) {
std::cout << "Unknown register in MOV Ev, Iv.\n";
error_flag = true;
running = false;
return;
}
*reg = immediate;
}
}
// Реализация инструкции INC r/m32
void Emulator::instr_INC_rm32(uint8_t modrm) {
Operand operand = decode_operand(modrm);
if (operand.is_memory) {
uint32_t value = read_memory_dword(operand.address);
value++;
write_memory_dword(operand.address, value);
}
else {
uint32_t* reg = get_register_by_code(operand.register_code);
(*reg)++;
}
update_ZF(operand.is_memory ? read_memory_dword(operand.address) : *get_register_by_code(operand.register_code));
}
// Реализация инструкции DEC r/m32
void Emulator::instr_DEC_rm32(uint8_t modrm) {
Operand operand = decode_operand(modrm);
if (operand.is_memory) {
uint32_t value = read_memory_dword(operand.address);
value--;
write_memory_dword(operand.address, value);
}
else {
uint32_t* reg = get_register_by_code(operand.register_code);
(*reg)--;
}
update_ZF(operand.is_memory ? read_memory_dword(operand.address) : *get_register_by_code(operand.register_code));
}
void Emulator::instr_LEAVE() {
// Set ESP to EBP
regs.ESP = regs.EBP;
// POP EBP
if (regs.ESP + 4 > memory.size()) {
std::cerr << "Stack underflow on LEAVE.\n";
error_flag = true;
running = false;
return;
}
regs.EBP = read_memory_dword(regs.ESP);
regs.ESP += 4;
std::cout << "Выполнена инструкция LEAVE. ESP: 0x" << std::hex << regs.ESP
<< ", EBP: 0x" << regs.EBP << "\n";
}
// Реализация инструкции CALL r/m32
void Emulator::instr_CALL_rm32(uint8_t modrm) {
Operand operand = decode_operand(modrm);
uint32_t address = operand.is_memory ? read_memory_dword(operand.address) : *get_register_by_code(operand.register_code);
// Сохраняем текущий адрес возврата в стек
push(regs.EIP);
// Переходим к новому адресу
regs.EIP = address;
}
// Реализация инструкции JMP r/m32
void Emulator::instr_JMP_rm32(uint8_t modrm) {
Operand operand = decode_operand(modrm);
uint32_t address = operand.is_memory ? read_memory_dword(operand.address) : *get_register_by_code(operand.register_code);
regs.EIP = address;
}
// Реализация инструкции PUSH r/m32
void Emulator::instr_PUSH_rm32(uint8_t modrm) {
Operand operand = decode_operand(modrm);
uint32_t value = operand.is_memory ? read_memory_dword(operand.address) : *get_register_by_code(operand.register_code);
push(value);
}
void Emulator::instr_PUSH_imm32() {
uint32_t imm32 = fetch_dword(); // Чтение 32-битного непосредственного значения
push(imm32); // Помещение значения в стек
}
void Emulator::instr_GROUP5() {
uint8_t modrm = fetch_byte();
uint8_t mod = (modrm >> 6) & 0x03;
uint8_t reg = (modrm >> 3) & 0x07; // Поле reg в ModR/M указывает на операцию
uint8_t rm = modrm & 0x07;
switch (reg) {
case 0: // INC r/m32
instr_INC_rm32(modrm);
break;
case 1: // DEC r/m32
instr_DEC_rm32(modrm);
break;
case 2: // CALL r/m32
instr_CALL_rm32(modrm);
break;
case 3: // CALL far
std::cout << "CALL far не поддерживается.\n";
error_flag = true;
running = false;
break;
case 4: // JMP r/m32
instr_JMP_rm32(modrm);
break;
case 5: // JMP far
std::cout << "JMP far не поддерживается.\n";
error_flag = true;
running = false;
break;
case 6: // PUSH r/m32
instr_PUSH_rm32(modrm);
break;
default:
std::cout << "Неизвестный подтип команды 0xFF: " << (int)reg << "\n";
error_flag = true;
running = false;
break;
}
}
void Emulator::instr_ENDBR32() {
// Мы уже обработали префикс 0xF3 и прочитали опкод 0x0F
// Теперь нужно убедиться, что следующий байт 0x1E, уже считан
// Считываем последний байт инструкции
uint8_t modrm = fetch_byte();
if (modrm != 0xFB) {
std::cout << "Ожидаемый байт 0xFB не найден после opcode 0x1E для ENDBR32.\n";
error_flag = true;
running = false;
return;
}
// Инструкция корректно распознана, выполняем NOP
std::cout << "Выполнена инструкция ENDBR32 (пропущена).\n";
}
void Emulator::instr_STD() {
// Set the Direction Flag (DF), which is bit 10 in EFLAGS
regs.EFLAGS |= DF;
std::cout << "Выполнена инструкция STD (Direction Flag установлен).\n";
}
void Emulator::instr_NOP() {
// NOP does nothing
std::cout << "Выполнена инструкция NOP.\n";
}
void Emulator::instr_PUSHAD() {
uint32_t temp_esp = regs.ESP;
push(regs.EAX);
push(regs.ECX);
push(regs.EDX);
push(regs.EBX);
push(temp_esp); // Original value of ESP
push(regs.EBP);
push(regs.ESI);
push(regs.EDI);
std::cout << "Выполнена инструкция PUSHAD.\n";
}
void Emulator::instr_REP_MOVSB() {
while (regs.ECX != 0) {
uint8_t byte = read_memory_byte(regs.ESI);
write_memory_byte(regs.EDI, byte);
// Update ESI and EDI based on the Direction Flag
if (regs.EFLAGS & DF) {
regs.ESI -= 1;
regs.EDI -= 1;
}
else {
regs.ESI += 1;
regs.EDI += 1;
}
regs.ECX -= 1;
}
std::cout << "Выполнена инструкция REP MOVSB.\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();
uint8_t mod = (modrm >> 6) & 0x03;
if (mod == 3) {
// Mod == 3 означает, что операнд — регистр
// В этом случае NOP не делает ничего
uint8_t rm = modrm & 0x07;
// Можно просто считать регистр для эмуляции чтения
uint32_t* reg = get_register_by_code(rm);
if (reg) {
uint32_t temp = *reg;
// NOP ничего не делает, поэтому не изменяем значение
}
else {
std::cout << "Неизвестный регистр в NOP r/m32.\n";
error_flag = true;
running = false;
return;
}
}
else {
// Если Mod != 3, то вычисляем адрес и читаем операнд из памяти
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() {
if (regs.rep_prefix || regs.repne_prefix) {
std::cout << "Warning: REP prefix is ignored for ADD EAX, imm32.\n";
reset_prefixes();
}
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;
uint8_t reg = (modrm >> 3) & 0x07; // Destination register code
uint8_t rm = modrm & 0x07; // Source operand
// LEA is invalid with mod == 3 (register-direct mode)
if (mod == 3) {
std::cout << "Invalid LEA instruction with mod == 3.\n";
error_flag = true;
running = false;
return;
}
// 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*>(®s.EAX);
*al += imm8;
update_ZF(*al); // Обновляем флаг ZF на основе 8-битного результата
}
void Emulator::instr_POP_EBP() {
if (regs.ESP + 4 > memory.size()) {
std::cerr << "Stack underflow on POP EBP.\n";
error_flag = true;
running = false;
return;
}
// Pop the value from the stack into EBP
regs.EBP = read_memory_dword(regs.ESP);
regs.ESP += 4;
std::cout << "Выполнен POP EBP. Значение в регистре EBP: 0x" << std::hex << regs.EBP << "\n";
}
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 1: // sys_exit
running = false;
break;
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 в случае ошибки
}
}
case 4: { // sys_write
uint32_t fd = regs.EBX;
uint32_t buf = regs.ECX;
uint32_t count = regs.EDX;
// Debug output
std::cout << "sys_write called with fd=" << fd
<< ", buf=0x" << std::hex << buf
<< ", count=" << std::dec << count << "\n";
if (fd == 1) { // stdout
// Ensure the buffer address is within memory bounds
if (buf + count > memory.size()) {
std::cout << "Buffer out of bounds in sys_write.\n";
regs.EAX = -1; // Return -1 on error
break;
}
std::string output;
for (uint32_t i = 0; i < count; ++i) {
output += static_cast<char>(memory[buf + i]);
}
std::cout << output; // Output the string
// Return the number of bytes written
regs.EAX = count;
}
else {
std::cout << "Unsupported file descriptor in sys_write: " << fd << "\n";
regs.EAX = -1; // Return -1 on error
}
break;
}
case 45: { // sys_brk
uint32_t addr = regs.EBX;
if (addr == 0) {
// Возвращаем текущий адрес brk
regs.EAX = current_brk;
}
else {
// Устанавливаем новый адрес brk
if (addr >= data_segment_start && addr < memory.size()) {
current_brk = addr;
regs.EAX = current_brk;
}
else {
// Ошибка: попытка установить brk за пределами памяти
regs.EAX = 0; // Ошибка
}
}
break;
}
case 90: // sys_mmap
// Реализация sys_mmap
break;
case 91: { // sys_munmap
uint32_t addr = regs.EBX;
uint32_t length = regs.ECX;
// Для простоты, можно игнорировать освобождение памяти
regs.EAX = 0;
break;
}
case 5: { // sys_open
const char* filename = reinterpret_cast<const char*>(&memory[regs.EBX]); // Путь к файлу
uint32_t flags = regs.ECX;
uint32_t mode = regs.EDX;
// Для простоты, возвращаем фиктивный файловый дескриптор, например 3
regs.EAX = 3;
break;
}
case 6: { // sys_close
uint32_t fd = regs.EBX;
// Ничего не делаем, возвращаем успех
regs.EAX = 0;
break;
}
case 192: { // sys_mmap2
uint32_t addr = regs.EBX;
uint32_t length = regs.ECX;
uint32_t prot = regs.EDX;
uint32_t flags = regs.ESI;
uint32_t fd = regs.EDI;
uint32_t pgoffset = regs.EBP;
// Если addr равен 0, выбираем свободный адрес
if (addr == 0) {
addr = allocate_memory(0, length);
}
else {
// Проверяем, можем ли мы выделить память по запрошенному адресу
addr = allocate_memory(addr, length);
}
if (addr == 0) {
// Ошибка при выделении памяти
regs.EAX = -1;
}
else {
// Успешное выделение памяти
regs.EAX = addr;
}
break;
}
case 195: // sys_fstat
// Реализация sys_fstat
break;
case 197: { // sys_fstat64
uint32_t fd = regs.EBX;
uint32_t buf = regs.ECX;
// Возвращаем фиктивные данные
// В структуре struct stat64 около 104 байт
memset(&memory[buf], 0, 104);
regs.EAX = 0;
break;
}
default:
std::cout << "Неизвестный системный вызов: " << syscall_number << "\n";
running = false;
break;
}
}
else {
std::cout << "Неизвестное прерывание: INT " << (int)int_number << "\n";
error_flag = true;
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*>(®s.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 = (modrm >> 3) & 0x07; // Destination register (r32)
uint8_t rm = modrm & 0x07; // Source (r/m32)
uint32_t* dest_reg = get_register_by_code(reg);
if (mod == 3) { // Register-register mode
uint32_t* src_reg = get_register_by_code(rm);
if (dest_reg && src_reg) {
*dest_reg = *src_reg;
}
else {
std::cout << "Unknown register in MOV r32, r/m32.\n";
error_flag = true;
running = false;
}
}
else { // Memory to register
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 << "Unknown destination register in MOV r32, r/m32.\n";
error_flag = true;
running = false;
}
}
}
void Emulator::instr_ADD_r32_rm32() {
uint8_t modrm = fetch_byte();
Operand operand = decode_operand(modrm); // Предполагается, что вы реализовали структуру Operand
uint8_t reg_code = (modrm >> 3) & 0x07;
uint8_t rm_code = modrm & 0x07;
uint32_t* reg = get_register_by_code(reg_code);
if (!reg) {
std::cout << "Unknown destination register in ADD r32, r/m32.\n";
error_flag = true;
running = false;
return;
}
if (operand.is_memory) {
uint32_t value = read_memory_dword(operand.address);
*reg += value;
}
else {
uint32_t* src_reg = get_register_by_code(rm_code);
if (!src_reg) {
std::cout << "Unknown source register in ADD r32, r/m32.\n";
error_flag = true;
running = false;
return;
}
*reg += *src_reg;
}
update_ZF(*reg);
// Обновите другие флаги при необходимости
}
void Emulator::instr_ADD_rm32_r32() {
bool is_locked = regs.lock_prefix;
uint8_t modrm = fetch_byte();
uint8_t mod = (modrm >> 6) & 0x03;
uint8_t reg_code = (modrm >> 3) & 0x07; // Source register (r32)
uint8_t rm_code = modrm & 0x07; // Destination (r/m32)
uint32_t* src_reg = get_register_by_code(reg_code);
if (mod == 3) { // Register-register mode
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);
// Update other flags as needed
}
else {
std::cout << "Unknown register in ADD r/m32, r32.\n";
error_flag = true;
running = false;
}
}
else { // Memory operand
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);
// Update other flags as needed
}
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() {
int32_t rel32 = fetch_dword();
// Push the next instruction address onto the stack
push(regs.EIP);
// 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_ADD_rm8_r8() {
uint8_t modrm = fetch_byte();
uint8_t mod = (modrm >> 6) & 0x03;
uint8_t reg_code = (modrm >> 3) & 0x07; // Source register (r8)
uint8_t rm = modrm & 0x07; // Destination (r/m8)
uint8_t* src_reg = get_register8_by_code(reg_code);
if (!src_reg) {
std::cout << "Unknown source register in ADD r/m8, r8.\n";
error_flag = true;
running = false;
return;
}
if (mod == 3) { // Register to register
uint8_t* dest_reg = get_register8_by_code(rm);
if (!dest_reg) {
std::cout << "Unknown destination register in ADD r/m8, r8.\n";
error_flag = true;
running = false;
return;
}
*dest_reg += *src_reg;
update_ZF(*dest_reg);
}
else {
// Memory operand
uint32_t address = calculate_address(modrm);
if (error_flag) return;
uint8_t value = read_memory_byte(address);
value += *src_reg;
write_memory_byte(address, value);
update_ZF(value);
}
// Update other flags (CF, OF, etc.) as necessary
}
// XOR AL, imm8
void Emulator::instr_XOR_AL_imm8() {
uint8_t imm8 = fetch_byte();
uint8_t* al = reinterpret_cast<uint8_t*>(®s.EAX); // Access the AL register
*al ^= imm8; // Perform XOR operation
// Update Zero Flag (ZF)
if (*al == 0)
regs.EFLAGS |= ZF;
else
regs.EFLAGS &= ~ZF;
// Update Sign Flag (SF)
if (*al & 0x80)
regs.EFLAGS |= SF;
else
regs.EFLAGS &= ~SF;
// Parity Flag (PF)
update_PF(*al);
// Clear Carry Flag (CF) and Overflow Flag (OF) as XOR resets them
regs.EFLAGS &= ~CF;
regs.EFLAGS &= ~OF;
std::cout << "Выполнена инструкция XOR AL, imm8. AL: 0x" << std::hex << static_cast<int>(*al) << "\n";
}
// Function to update Parity Flag based on the result
void Emulator::update_PF(uint8_t result) {
// Count the number of set bits
result ^= result >> 4;
result &= 0xF;
bool parity = (0x6996 >> result) & 1;
if (parity)
regs.EFLAGS |= PF; // PF is set if parity is even
else
regs.EFLAGS &= ~PF;
}
void Emulator::instr_AND_rm8_r8() {
uint8_t modrm = fetch_byte();
uint8_t mod = (modrm >> 6) & 0x03;
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 source register in AND r/m8, r8.\n";
error_flag = true;
running = false;
return;
}
if (mod == 3) { // Режим регистр-регистр
uint8_t* dest_reg = get_register8_by_code(rm);
if (!dest_reg) {
std::cout << "Unknown destination register in AND r/m8, r8.\n";
error_flag = true;
running = false;
return;
}
*dest_reg &= *reg;
update_ZF(*dest_reg);
}
else {
// Операнд - память
uint32_t address = calculate_address(modrm);
if (error_flag) return;
uint8_t value = read_memory_byte(address);
value &= *reg;
write_memory_byte(address, value);
update_ZF(value);
}
// Обновление флагов
// Обновите флаги SF, PF, CF, OF по необходимости
// Флаги CF и OF сбрасываются при логических операциях
regs.EFLAGS &= ~(CF | OF);
// Обновление SF
if ((value & 0x80) != 0)
regs.EFLAGS |= SF;
else
regs.EFLAGS &= ~SF;
// Обновление PF
update_PF(value);
std::cout << "Выполнена инструкция AND r/m8, r8.\n";
}
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;
}
}
}
#ifndef EMULATOR_H
#define EMULATOR_H
#include <vector>
#include <unordered_map>
#include <functional>
#include <cstdint>
class Emulator {
public:
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
};
struct Operand {
bool is_memory;
uint32_t address; // Если is_memory = true
uint32_t register_code; // Если is_memory = false
};
Operand decode_operand(uint8_t modrm);
Emulator(size_t memory_size);
void load_program(const std::vector<uint8_t>& program, size_t load_address, bool set_eip);
void run();
void print_registers(bool hex_output = false) const;
bool has_error() const { return error_flag; }
// Добавленные методы
void write_memory(uint32_t address, const uint8_t* data, size_t size);
size_t get_memory_size() const { return memory.size(); }
void set_eip(uint32_t address);
void reset_prefixes();
void initialize_stack();
struct Registers {
uint32_t EAX, EBX, ECX, EDX, ESI, EDI, ESP, EBP;
uint32_t EIP;
uint32_t EFLAGS;
// Сегментные регистры
uint32_t CS;
uint32_t DS;
uint32_t SS;
uint32_t ES;
uint32_t FS;
uint32_t GS;
// Флаги для префиксов
bool lock_prefix = false;
bool rep_prefix = false;
bool repne_prefix = false;
bool operand_size_override = false;
bool address_size_override = false;
// Конструктор для инициализации сегментных регистров
Registers() : EAX(0), EBX(0), ECX(0), EDX(0),
ESI(0), EDI(0), ESP(0), EBP(0),
EIP(0), EFLAGS(0),
CS(0), DS(0), SS(0), ES(0), FS(0), GS(0) {}
} regs;
private:
std::vector<uint8_t> memory;
bool running = false;
bool error_flag = false;
uint32_t current_brk = 0;
uint32_t data_segment_start = 0x08000000; // Начальный адрес сегмента данных
// Метод для сброса сегментных префиксов
void reset_segment_override();
// Метод для установки сегментного префикса
void set_segment_override(uint8_t prefix);
// Flags
static constexpr uint32_t ZF = 1 << 6; // Zero Flag
static constexpr uint32_t CF = 1 << 0; // Carry Flag
static constexpr uint32_t DF = 1 << 10; // Direction Flag
static constexpr uint32_t SF = 1 << 7; // Sign Flag
static constexpr uint32_t OF = 1 << 11; // Overflow Flag
static constexpr uint32_t IF_FLAG = 1 << 9; // Interrupt Flag
static constexpr uint32_t PF = 1 << 2; // Parity Flag
// Instruction handling
typedef void (Emulator::* InstructionHandler)();
std::unordered_map<uint8_t, InstructionHandler> instruction_set;
std::unordered_map<uint8_t, InstructionHandler> extended_instruction_set;
void initialize_instruction_set();
// Объявление указателей на текущие сегменты
uint32_t* current_data_segment;
uint32_t* current_code_segment;
// Instruction implementations
// [Ваши существующие методы обработчиков инструкций]
void instr_MOV_Ev_Iv();
void instr_MOV_EAX_imm32();
void instr_MOV_EBX_imm32();
void instr_MOV_ECX_imm32();
void instr_MOV_EDX_imm32();
void instr_ADD_EAX_imm32();
void instr_SUB_EAX_imm32();
void instr_INC_EAX();
void instr_DEC_EAX();
void instr_MUL_EAX(); // Not used
void instr_JMP_rel32();
void instr_CMP_reg_imm8();
void instr_JE_rel8();
void instr_JNE_rel8();
void instr_AND_EAX_imm32();
void instr_AND_ECX_imm32();
void instr_OR_EAX_imm32();
void instr_XOR_EAX_imm32();
void instr_SUB_r32_imm32();
void instr_CMP_EAX_imm32();
void instr_OR_ECX_imm32();
void instr_RET(); // Обработчик RET
void instr_MOV_MEM_EAX(); // MOV [address], EAX
void instr_MOV_EAX_MEM(); // MOV EAX, [address]
void instr_CMP_EAX_EBX();
void instr_JG_rel8(); // JG rel8
void instr_JL_rel8(); // JL rel8
void instr_CMP_r32_rm32();
void instr_IMUL_reg_rm32_imm32();
void instr_JB_rel8();
void instr_JA_rel8();
void instr_INC_ECX();
void instr_JMP_rel8();
void instr_MOV_r8_imm8();
void instr_SUB_AL_imm8();
void instr_SUB_rm8_imm8();
void instr_MOV_rm8_r8();
void instr_MOV_rm8_imm8();
void instr_MOV_r8_rm8();
void instr_ADD_AL_imm8();
void instr_MOV_ESI_imm32();
void instr_INT();
void instr_F7();
void instr_MUL_rm32(uint8_t modrm);
void instr_DIV_rm32(uint8_t modrm);
void instr_IDIV_rm32(uint8_t modrm);
void instr_XOR_r32_rm32();
void instr_MOV_r32_rm32();
void instr_ADD_rm32_r32();
void instr_CMP_AL_imm8();
void instr_ADD_r32_rm32();
void instr_SUB_EBX_imm32();
void instr_IMUL_reg_rm32_imm8();
void instr_MOV_r32_r_m32();
void instr_MOV_EBP_imm32();
void instr_MOV_ESP_imm32();
void instr_MOV_EDI_imm32();
void instr_CALL_rel32();
void instr_GROUP1_Ev_Iz_81();
void instr_GROUP1_Ev_Iz_83();
void instr_LEA_r32_m();
void instr_MOVSB();
void instr_JNE_rel32();
void instr_JG_rel32();
void instr_JE_rel32();
void instr_NOP_EAX();
void instr_NOP_m16_m32();
void instr_JL_rel32();
void instr_STI();
void instr_ENDBR32();
void instr_PUSH_EDI();
void instr_PUSH_ESI();
void instr_PUSH_EBP();
void instr_PUSH_EBX();
void instr_PUSH_EDX();
void instr_PUSH_ECX();
void instr_PUSH_EAX();
void instr_PUSH_ESP();
void instr_POP_EAX();
void instr_POP_ECX();
void instr_POP_EDX();
void instr_POP_EBX();
void instr_POP_ESP();
void instr_POP_EBP();
void instr_POP_ESI();
void instr_POP_EDI();
void instr_PUSH_imm8();
void instr_GROUP5();
void instr_INC_rm32(uint8_t modrm);
void instr_DEC_rm32(uint8_t modrm);
void instr_CALL_rm32(uint8_t modrm);
void instr_JMP_rm32(uint8_t modrm);
void instr_PUSH_rm32(uint8_t modrm);
void instr_PUSH_imm32();
void instr_ADD_rm8_r8();
void instr_CLD();
void instr_NOP();
void instr_STD();
void instr_PUSHAD();
void instr_REP_MOVSB();
void instr_XOR_AL_imm8();
void instr_LEAVE();
void instr_AND_rm8_r8();
// Utility methods
uint8_t fetch_byte();
uint32_t fetch_dword();
uint32_t* get_register_by_code(uint8_t code);
uint8_t* get_register8_by_code(uint8_t code);
uint8_t regm_rm(uint8_t modrm);
uint32_t calculate_address(uint8_t modrm);
uint32_t calculate_sib_address(uint8_t mod, uint8_t sib, int32_t displacement);
void update_ZF(uint32_t result);
void update_PF(uint8_t result);
uint8_t read_memory_byte(uint32_t address) const;
uint32_t read_memory_dword(uint32_t address) const;
void write_memory_dword(uint32_t address, uint32_t value);
void write_memory_byte(uint32_t address, uint8_t value);
uint32_t allocate_memory(uint32_t addr, uint32_t length);
void push(uint32_t value);
};
#endif // EMULATOR_H
// 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 - 16); // Отступаем на 16 байт от конца памяти
initialize_stack();
regs.CS = 0;
regs.DS = 0;
regs.SS = 0;
regs.ES = 0;
regs.FS = 0;
regs.GS = 0;
current_data_segment = ®s.DS;
current_code_segment = ®s.CS;
current_brk = data_segment_start;
}
uint32_t Emulator::allocate_memory(uint32_t addr, uint32_t length) {
// Простая реализация: просто сдвигаем brk
if (addr == 0) {
addr = current_brk;
}
uint32_t new_brk = addr + length;
if (new_brk > memory.size()) {
// Недостаточно памяти в эмуляторе
return 0;
}
current_brk = new_brk;
return addr;
}
void Emulator::set_segment_override(uint8_t prefix) {
switch (prefix) {
case 0x2E: // CS
current_code_segment = ®s.CS;
break;
case 0x36: // SS
current_data_segment = ®s.SS;
break;
case 0x3E: // DS
current_data_segment = ®s.DS;
break;
case 0x26: // ES
current_data_segment = ®s.ES;
break;
case 0x64: // FS
current_data_segment = ®s.FS;
break;
case 0x65: // GS
current_data_segment = ®s.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 {
std::cout << "EIP: 0x" << std::hex << regs.EIP << "\n";
std::cout << "ESP: " << std::hex << regs.ESP << ", Значение на вершине стека: " << read_memory_dword(regs.ESP) << "\n";
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";
// Проверяем на ENDBR32
if (opcode == 0xF3) {
uint8_t next_opcode = memory[regs.EIP];
if (next_opcode == 0x0F) {
// Потенциально ENDBR32, прерываем сбор префиксов
break;
}
}
opcode = fetch_byte(); // Читаем следующий байт как опкод инструкции
}
// Проверяем на ENDBR32
if (regs.rep_prefix && memory[regs.EIP] == 0x0F) {
regs.EIP++; // Пропускаем 0x0F
uint8_t opcode1 = fetch_byte(); // Считываем следующий байт
if (opcode1 == 0x1E) {
instr_ENDBR32();
continue; // Переходим к следующей инструкции
}
else {
std::cout << "Неизвестный opcode: 0x" << std::hex << (int)opcode1 << "\n";
error_flag = true;
running = false;
continue;
}
}
// Проверка на двухбайтовый опкод
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;
}
}
print_registers(true);
std::cout << "EFLAGS: 0x" << std::hex << regs.EFLAGS << std::endl;
// После выполнения инструкции сбросить префиксы
reset_segment_override();
reset_prefixes();
}
catch (const std::exception& e) {
std::cerr << "Exception caught: " << e.what() << "\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 = ®s.DS;
current_code_segment = ®s.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 if (mod == 3) {
// Mod == 3 indicates register-direct mode, address calculation is not applicable.
std::cout << "Error: calculate_address() called with mod == 3 (register-direct mode) which is invalid for memory addressing.\n";
error_flag = true;
running = false;
return 0;
}
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[0xC7] = &Emulator::instr_MOV_Ev_Iv;
instruction_set[0x34] = &Emulator::instr_XOR_AL_imm8;
instruction_set[0x50] = &Emulator::instr_PUSH_EAX;
instruction_set[0x51] = &Emulator::instr_PUSH_ECX;
instruction_set[0x52] = &Emulator::instr_PUSH_EDX;
instruction_set[0x53] = &Emulator::instr_PUSH_EBX;
instruction_set[0x54] = &Emulator::instr_PUSH_ESP;
instruction_set[0x55] = &Emulator::instr_PUSH_EBP;
instruction_set[0x56] = &Emulator::instr_PUSH_ESI;
instruction_set[0x57] = &Emulator::instr_PUSH_EDI;
instruction_set[0x6A] = &Emulator::instr_PUSH_imm8;
instruction_set[0x58] = &Emulator::instr_POP_EAX;
instruction_set[0x59] = &Emulator::instr_POP_ECX;
instruction_set[0x5A] = &Emulator::instr_POP_EDX;
instruction_set[0x5B] = &Emulator::instr_POP_EBX;
instruction_set[0x5C] = &Emulator::instr_POP_ESP;
instruction_set[0x5D] = &Emulator::instr_POP_EBP;
instruction_set[0x5E] = &Emulator::instr_POP_ESI;
instruction_set[0x5F] = &Emulator::instr_POP_EDI;
instruction_set[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;
instruction_set[0x5E] = &Emulator::instr_POP_ESI;
instruction_set[0xFF] = &Emulator::instr_GROUP5;
instruction_set[0x68] = &Emulator::instr_PUSH_imm32;
instruction_set[0x00] = &Emulator::instr_ADD_rm8_r8; // ADD r/m8, r8
instruction_set[0xFC] = &Emulator::instr_CLD;
instruction_set[0x90] = &Emulator::instr_NOP;
instruction_set[0xFD] = &Emulator::instr_STD;
instruction_set[0x60] = &Emulator::instr_PUSHAD;
instruction_set[0x5D] = &Emulator::instr_POP_EBP;
instruction_set[0xFB] = &Emulator::instr_STI;
instruction_set[0xC9] = &Emulator::instr_LEAVE;
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_m16_m32;
extended_instruction_set[0x1E] = &Emulator::instr_ENDBR32;
}
void Emulator::initialize_stack() {
// Установим ESP немного ниже конца памяти
uint32_t stack_top = memory.size() - 16;
// Инициализируем стек значениями argc и argv
uint32_t argc = 0; // Можно установить 0, если вы не передаёте аргументы
uint32_t argv_ptr = 0; // Адрес argv (можно установить в 0)
// Записываем argc на вершину стека
regs.ESP = stack_top - 4;
write_memory_dword(regs.ESP, argc);
// Можно добавить дополнительные данные, если это необходимо
}
Emulator::Operand Emulator::decode_operand(uint8_t modrm) {
Operand operand;
uint8_t mod = (modrm >> 6) & 0x03;
uint8_t rm = modrm & 0x07;
if (mod == 3) { // Регистр-режим
operand.is_memory = false;
operand.register_code = rm;
}
else { // Память
operand.is_memory = true;
operand.address = calculate_address(modrm);
}
return operand;
}
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 ®s.EAX;
case 1: return ®s.ECX;
case 2: return ®s.EDX;
case 3: return ®s.EBX;
case 4: return ®s.ESP;
case 5: return ®s.EBP;
case 6: return ®s.ESI;
case 7: return ®s.EDI;
default: return nullptr;
}
}
uint8_t* Emulator::get_register8_by_code(uint8_t code) {
switch (code) {
case 0: return reinterpret_cast<uint8_t*>(®s.EAX); // AL
case 1: return reinterpret_cast<uint8_t*>(®s.ECX); // CL
case 2: return reinterpret_cast<uint8_t*>(®s.EDX); // DL
case 3: return reinterpret_cast<uint8_t*>(®s.EBX); // BL
case 4: return reinterpret_cast<uint8_t*>(®s.EAX) + 1; // AH
case 5: return reinterpret_cast<uint8_t*>(®s.ECX) + 1; // CH
case 6: return reinterpret_cast<uint8_t*>(®s.EDX) + 1; // DH
case 7: return reinterpret_cast<uint8_t*>(®s.EBX) + 1; // BH
default: return nullptr;
}
}
uint8_t Emulator::regm_rm(uint8_t modrm) {
return modrm & 0x07; // Извлекаем регистровый код (rm)
}
Серьезность Код Описание Проект Файл Строка Состояние подавления Подробности
Ошибка (активно) E0020 идентификатор "value" не определен x86_Emulator C:\Users\Swed\source\repos\x86_Emulator\Instructions.cpp 1935
C:\Users\Swed\source\repos\x86_Emulator\x64\Debug>x86_Emulator.exe main2.elf
Запуск программы из файла: main2.elf...
Объем выделенной памяти эмулятора: 1024 MB
ELF-файл успешно загружен. Точка входа: 0x80495b0
EIP: 0x80495b0
ESP: 3fffffec, Значение на вершине стека: 0
Обнаружен префикс: 0xf3
Выполнена инструкция ENDBR32 (пропущена).
EIP: 0x80495b4
ESP: 3fffffec, Значение на вершине стека: 0
EAX: 0x0
EBX: 0x0
ECX: 0x0
EDX: 0x0
ESI: 0x0
EDI: 0x0
ESP: 0x3fffffec
EBP: 0x0
EIP: 0x80495b6
EFLAGS: 0x40
EFLAGS: 0x40
EIP: 0x80495b6
ESP: 3fffffec, Значение на вершине стека: 0
Выполнен POP ESI. Значение в регистре ESI: 0
EAX: 0x0
EBX: 0x0
ECX: 0x0
EDX: 0x0
ESI: 0x0
EDI: 0x0
ESP: 0x3ffffff0
EBP: 0x0
EIP: 0x80495b7
EFLAGS: 0x40
EFLAGS: 0x40
EIP: 0x80495b7
ESP: 3ffffff0, Значение на вершине стека: 0
EAX: 0x0
EBX: 0x0
ECX: 0x3ffffff0
EDX: 0x0
ESI: 0x0
EDI: 0x0
ESP: 0x3ffffff0
EBP: 0x0
EIP: 0x80495b9
EFLAGS: 0x40
EFLAGS: 0x40
EIP: 0x80495b9
ESP: 3ffffff0, Значение на вершине стека: 0
EAX: 0x0
EBX: 0x0
ECX: 0x3ffffff0
EDX: 0x0
ESI: 0x0
EDI: 0x0
ESP: 0x3ffffff0
EBP: 0x0
EIP: 0x80495bc
EFLAGS: 0x0
EFLAGS: 0x0
EIP: 0x80495bc
ESP: 3ffffff0, Значение на вершине стека: 0
EAX: 0x0
EBX: 0x0
ECX: 0x3ffffff0
EDX: 0x0
ESI: 0x0
EDI: 0x0
ESP: 0x3fffffec
EBP: 0x0
EIP: 0x80495bd
EFLAGS: 0x0
EFLAGS: 0x0
EIP: 0x80495bd
ESP: 3fffffec, Значение на вершине стека: 0
EAX: 0x0
EBX: 0x0
ECX: 0x3ffffff0
EDX: 0x0
ESI: 0x0
EDI: 0x0
ESP: 0x3fffffe8
EBP: 0x0
EIP: 0x80495be
EFLAGS: 0x0
EFLAGS: 0x0
EIP: 0x80495be
ESP: 3fffffe8, Значение на вершине стека: 3fffffec
EAX: 0x0
EBX: 0x0
ECX: 0x3ffffff0
EDX: 0x0
ESI: 0x0
EDI: 0x0
ESP: 0x3fffffe4
EBP: 0x0
EIP: 0x80495bf
EFLAGS: 0x0
EFLAGS: 0x0
EIP: 0x80495bf
ESP: 3fffffe4, Значение на вершине стека: 0
EAX: 0x0
EBX: 0x0
ECX: 0x3ffffff0
EDX: 0x0
ESI: 0x0
EDI: 0x0
ESP: 0x3fffffe0
EBP: 0x0
EIP: 0x80495dd
EFLAGS: 0x0
EFLAGS: 0x0
EIP: 0x80495dd
ESP: 3fffffe0, Значение на вершине стека: 80495c4
EAX: 0x0
EBX: 0x80495c4
ECX: 0x3ffffff0
EDX: 0x0
ESI: 0x0
EDI: 0x0
ESP: 0x3fffffe0
EBP: 0x0
EIP: 0x80495e0
EFLAGS: 0x0
EFLAGS: 0x0
EIP: 0x80495e0
ESP: 3fffffe0, Значение на вершине стека: 80495c4
EAX: 0x0
EBX: 0x80495c4
ECX: 0x3ffffff0
EDX: 0x0
ESI: 0x0
EDI: 0x0
ESP: 0x3fffffe4
EBP: 0x0
EIP: 0x80495c4
EFLAGS: 0x0
EFLAGS: 0x0
EIP: 0x80495c4
ESP: 3fffffe4, Значение на вершине стека: 0
EAX: 0x0
EBX: 0x80ed000
ECX: 0x3ffffff0
EDX: 0x0
ESI: 0x0
EDI: 0x0
ESP: 0x3fffffe4
EBP: 0x0
EIP: 0x80495ca
EFLAGS: 0x0
EFLAGS: 0x0
EIP: 0x80495ca
ESP: 3fffffe4, Значение на вершине стека: 0
EAX: 0x0
EBX: 0x80ed000
ECX: 0x3ffffff0
EDX: 0x0
ESI: 0x0
EDI: 0x0
ESP: 0x3fffffe0
EBP: 0x0
EIP: 0x80495cc
EFLAGS: 0x0
EFLAGS: 0x0
EIP: 0x80495cc
ESP: 3fffffe0, Значение на вершине стека: 0
EAX: 0x0
EBX: 0x80ed000
ECX: 0x3ffffff0
EDX: 0x0
ESI: 0x0
EDI: 0x0
ESP: 0x3fffffdc
EBP: 0x0
EIP: 0x80495ce
EFLAGS: 0x0
EFLAGS: 0x0
EIP: 0x80495ce
ESP: 3fffffdc, Значение на вершине стека: 0
EAX: 0x0
EBX: 0x80ed000
ECX: 0x3ffffff0
EDX: 0x0
ESI: 0x0
EDI: 0x0
ESP: 0x3fffffd8
EBP: 0x0
EIP: 0x80495cf
EFLAGS: 0x0
EFLAGS: 0x0
EIP: 0x80495cf
ESP: 3fffffd8, Значение на вершине стека: 3ffffff0
EAX: 0x0
EBX: 0x80ed000
ECX: 0x3ffffff0
EDX: 0x0
ESI: 0x0
EDI: 0x0
ESP: 0x3fffffd4
EBP: 0x0
EIP: 0x80495d0
EFLAGS: 0x0
EFLAGS: 0x0
EIP: 0x80495d0
ESP: 3fffffd4, Значение на вершине стека: 0
EAX: 0x8049725
EBX: 0x80ed000
ECX: 0x3ffffff0
EDX: 0x0
ESI: 0x0
EDI: 0x0
ESP: 0x3fffffd4
EBP: 0x0
EIP: 0x80495d6
EFLAGS: 0x0
EFLAGS: 0x0
EIP: 0x80495d6
ESP: 3fffffd4, Значение на вершине стека: 0
EAX: 0x8049725
EBX: 0x80ed000
ECX: 0x3ffffff0
EDX: 0x0
ESI: 0x0
EDI: 0x0
ESP: 0x3fffffd0
EBP: 0x0
EIP: 0x80495d7
EFLAGS: 0x0
EFLAGS: 0x0
EIP: 0x80495d7
ESP: 3fffffd0, Значение на вершине стека: 8049725
EAX: 0x8049725
EBX: 0x80ed000
ECX: 0x3ffffff0
EDX: 0x0
ESI: 0x0
EDI: 0x0
ESP: 0x3fffffcc
EBP: 0x0
EIP: 0x804a980
EFLAGS: 0x0
EFLAGS: 0x0
EIP: 0x804a980
ESP: 3fffffcc, Значение на вершине стека: 80495dc
Обнаружен префикс: 0xf3
Выполнена инструкция ENDBR32 (пропущена).
EIP: 0x804a984
ESP: 3fffffcc, Значение на вершине стека: 80495dc
EAX: 0x8049725
EBX: 0x80ed000
ECX: 0x3ffffff0
EDX: 0x0
ESI: 0x0
EDI: 0x0
ESP: 0x3fffffc8
EBP: 0x0
EIP: 0x804a985
EFLAGS: 0x0
EFLAGS: 0x0
EIP: 0x804a985
ESP: 3fffffc8, Значение на вершине стека: 0
EAX: 0x8049725
EBX: 0x80ed000
ECX: 0x3ffffff0
EDX: 0x0
ESI: 0x0
EDI: 0x0
ESP: 0x3fffffc4
EBP: 0x0
EIP: 0x804a986
EFLAGS: 0x0
EFLAGS: 0x0
EIP: 0x804a986
ESP: 3fffffc4, Значение на вершине стека: 0
EAX: 0x8049725
EBX: 0x80ed000
ECX: 0x3ffffff0
EDX: 0x0
ESI: 0x0
EDI: 0x0
ESP: 0x3fffffc0
EBP: 0x0
EIP: 0x804a987
EFLAGS: 0x0
EFLAGS: 0x0
EIP: 0x804a987
ESP: 3fffffc0, Значение на вершине стека: 0
EAX: 0x8049725
EBX: 0x80ed000
ECX: 0x3ffffff0
EDX: 0x0
ESI: 0x0
EDI: 0x0
ESP: 0x3fffffbc
EBP: 0x0
EIP: 0x804ba87
EFLAGS: 0x0
EFLAGS: 0x0
EIP: 0x804ba87
ESP: 3fffffbc, Значение на вершине стека: 804a98c
EAX: 0x8049725
EBX: 0x80ed000
ECX: 0x3ffffff0
EDX: 0x0
ESI: 0x804a98c
EDI: 0x0
ESP: 0x3fffffbc
EBP: 0x0
EIP: 0x804ba8a
EFLAGS: 0x0
EFLAGS: 0x0
EIP: 0x804ba8a
ESP: 3fffffbc, Значение на вершине стека: 804a98c
EAX: 0x8049725
EBX: 0x80ed000
ECX: 0x3ffffff0
EDX: 0x0
ESI: 0x804a98c
EDI: 0x0
ESP: 0x3fffffc0
EBP: 0x0
EIP: 0x804a98c
EFLAGS: 0x0
EFLAGS: 0x0
EIP: 0x804a98c
ESP: 3fffffc0, Значение на вершине стека: 0
EAX: 0x8049725
EBX: 0x80ed000
ECX: 0x3ffffff0
EDX: 0x0
ESI: 0x80ed000
EDI: 0x0
ESP: 0x3fffffc0
EBP: 0x0
EIP: 0x804a992
EFLAGS: 0x0
EFLAGS: 0x0
EIP: 0x804a992
ESP: 3fffffc0, Значение на вершине стека: 0
EAX: 0x8049725
EBX: 0x80ed000
ECX: 0x3ffffff0
EDX: 0x0
ESI: 0x80ed000
EDI: 0x0
ESP: 0x3fffffbc
EBP: 0x0
EIP: 0x804a993
EFLAGS: 0x0
EFLAGS: 0x0
EIP: 0x804a993
ESP: 3fffffbc, Значение на вершине стека: 80ed000
EAX: 0x8049725
EBX: 0x80ed000
ECX: 0x3ffffff0
EDX: 0x0
ESI: 0x80ed000
EDI: 0x0
ESP: 0x3fffff30
EBP: 0x0
EIP: 0x804a999
EFLAGS: 0x0
EFLAGS: 0x0
EIP: 0x804a999
ESP: 3fffff30, Значение на вершине стека: 0
EAX: 0x0
EBX: 0x80ed000
ECX: 0x3ffffff0
EDX: 0x0
ESI: 0x80ed000
EDI: 0x0
ESP: 0x3fffff30
EBP: 0x0
EIP: 0x804a9a0
EFLAGS: 0x0
EFLAGS: 0x0
EIP: 0x804a9a0
ESP: 3fffff30, Значение на вершине стека: 0
EAX: 0x0
EBX: 0x80ed000
ECX: 0x0
EDX: 0x0
ESI: 0x80ed000
EDI: 0x0
ESP: 0x3fffff30
EBP: 0x0
EIP: 0x804a9a7
EFLAGS: 0x0
EFLAGS: 0x0
EIP: 0x804a9a7
ESP: 3fffff30, Значение на вершине стека: 0
EAX: 0x0
EBX: 0x80ed000
ECX: 0x0
EDX: 0x0
ESI: 0x80ed000
EDI: 0x0
ESP: 0x3fffff30
EBP: 0x0
EIP: 0x804a9ae
EFLAGS: 0x0
EFLAGS: 0x0
EIP: 0x804a9ae
ESP: 3fffff30, Значение на вершине стека: 0
EAX: 0x3ffffeb8
EBX: 0x80ed000
ECX: 0x0
EDX: 0x0
ESI: 0x80ed000
EDI: 0x0
ESP: 0x3fffff30
EBP: 0x0
EIP: 0x804a9b2
EFLAGS: 0x0
EFLAGS: 0x0
EIP: 0x804a9b2
ESP: 3fffff30, Значение на вершине стека: 0
EAX: 0x3ffffeb8
EBX: 0x80ed000
ECX: 0x0
EDX: 0x0
ESI: 0x80ed000
EDI: 0x0
ESP: 0x3fffff30
EBP: 0x0
EIP: 0x804a9b4
EFLAGS: 0x0
EFLAGS: 0x0
EIP: 0x804a9b4
ESP: 3fffff30, Значение на вершине стека: 0
Выполнена инструкция XOR AL, imm8. AL: 0x83
EAX: 0x3ffffe83
EBX: 0x80ed000
ECX: 0x0
EDX: 0x0
ESI: 0x80ed000
EDI: 0x0
ESP: 0x3fffff30
EBP: 0x0
EIP: 0x804a9b6
EFLAGS: 0x84
EFLAGS: 0x84
EIP: 0x804a9b6
ESP: 3fffff30, Значение на вершине стека: 0
EAX: 0x3ffffe83
EBX: 0x80ed000
ECX: 0x0
EDX: 0x0
ESI: 0x80ed000
EDI: 0x0
ESP: 0x3fffff30
EBP: 0x0
EIP: 0x804a9b8
EFLAGS: 0x84
EFLAGS: 0x84
EIP: 0x804a9b8
ESP: 3fffff30, Значение на вершине стека: 0
EAX: 0x3ffffe83
EBX: 0x80ed000
ECX: 0x0
EDX: 0x0
ESI: 0x80ed000
EDI: 0x0
ESP: 0x3fffff30
EBP: 0x0
EIP: 0x804a9ba
EFLAGS: 0x84
EFLAGS: 0x84
EIP: 0x804a9ba
ESP: 3fffff30, Значение на вершине стека: 0
Неизвестный opcode: 0x20
EAX: 0x3ffffe83
EBX: 0x80ed000
ECX: 0x0
EDX: 0x0
ESI: 0x80ed000
EDI: 0x0
ESP: 0x3fffff30
EBP: 0x0
EIP: 0x804a9bb
EFLAGS: 0x84
EFLAGS: 0x84
Программа из ELF-файла не выполнена.
На реальной системе:
swed@DESKTOP-K5N5PON:~$ ./main2.elf
Hello World!
swed@DESKTOP-K5N5PON:~$ cat main2.c
#include <unistd.h>
int main() {
const char* msg = "Hello World!\n";
write(1, msg, 13);
return 0;
}