ARM指令为4字节
THUMB指令为2字节
THUMB2 指令可能是2字节,也可能是4字节 (通过PC的最低bit位来检测)
问题1
在使用UNICORN模拟器 THUMB2 的时候,返回 UC_ERR_INSN_INVALID一定要检查当前设置PC值是不是正确
因为在unicorn_arm.c中对于
reg_write写入PC寄存器的时候
case UC_ARM_REG_R15:
ARM_CPU(uc, mycpu)->env.pc = (*(uint32_t *)value & ~1);
ARM_CPU(uc, mycpu)->env.thumb = (*(uint32_t *)value & 1);
ARM_CPU(uc, mycpu)->env.uc->thumb = (*(uint32_t *)value & 1);
ARM_CPU(uc, mycpu)->env.regs[15] = (*(uint32_t *)value & ~1);
// force to quit execution and flush TB
uc->quit_request = true;
uc_emu_stop(uc);
会通过检测PC寄存器的最低bit 为0或者1来确定当前是属于THUMB模式还是ARM模式 然后设置当前环境的模式。
所以如果是出于THUMB模式。一定要在PC上面+1。也就是说写PC寄存器的时候值应该为奇数
比如
err = uc_emu_start(uc, BASE + 0x12E2c + 1, BASE + 0x1BE64, 0, 0);
虽然指令的起始地址为0x12E2c 并且处于THUMB模式,那么实际上PC应该写 0x12E2c | 1 (和+1是一样的)
问题2
UNICORN遇到 VPUSH 等等指令返回 UC_ERR_INSN_INVALID
这是因为CPU是支持浮点操作的。但是UNICORN中浮点操作还没有开启。
所以要通过设置寄存器开启VFP
uint64_t tmp_val; err = uc_reg_read(uc, UC_ARM_REG_C1_C0_2, &tmp_val); if (err) { printf("uc_open %d\n", err); break; } tmp_val = tmp_val | (0xf << 20); err = uc_reg_write(uc, UC_ARM_REG_C1_C0_2, &tmp_val); if (err) { printf("uc_open %d\n", err); break; } size_t enable_vfp = 0x40000000; err = uc_reg_write(uc, UC_ARM_REG_FPEXC, &enable_vfp); if (err) { printf("uc_open %d\n", err); break; }
开启了浮点以后就可以开心运行了