arm 为 RISC ,指令长度定长为4字节
bit[25,28] 4bit为操作类型码,含义如下:
以第一个Data Processing -- Immediate (立即数数据处理)为例 ,bit[23,25]表示指令码,具体含义如下
以move指令为例 即bit [23,25] 为101 ,bit[23,28] 为100 101;
mov指令分为如下几类,有根据opc bit[29,30] 和 sf bit[31]来表示不同的mov指令,以movz指令为例,即010 ,bit[23,31] 为010 100 101
MOVZ sf指令 0/1 都是movz,sf指令代表 寄存器是32 bit还是64bit 0:32bit,1:64bit
32-bit variant
Applies when sf == 0.
MOVZ <Wd>, #<imm>{, LSL #<shift>}
64-bit variant
Applies when sf == 1.
MOVZ <Xd>, #<imm>{, LSL #<shift>}
Decode for all variants of this encoding
integer d = UInt(Rd);
integer datasize = if sf == '1' then 64 else 32;
integer pos;
if sf == '0' && hw<1> == '1' then UnallocatedEncoding();
pos = UInt(hw:'0000'); //表示hw 后追加4bit 0,也就是说hw为01, pos为010000;
Operation
bits(datasize) result;
result = Zeros();
result<pos+15:pos> = imm16;
X[d] = result;
MOVK MOVZ MOVN区别
对于立即数的指令选取
由上文知arm v8对于 立即数有限制,只能用16bit来存储立即数,可通过移位和取反操作来覆盖更多的立即数,只有覆盖不到的就会通过两条指令来完成赋值
MOVZ:
MOVN:
立即数范围 | 指令 | 指令码 | 备注 |
---|---|---|---|
高四16进制位全0:i {i取值 [0-0xffff]} |
movz w0,#0x1 | 0x52800020 0x529 |
hw位bit[21,22]为00b,表示不左移,bit[5,20] 为1,所以就是拷贝的 1 |
低四16进制位全0:(0xi0000 & 0xFFFF0000) {i取值 [1-0xffff]} |
movz w0,#0xfff f0000 |
0x52bfffe0 0x52a |
hw位bit[21,22]为01b,表示左移16bit,bit[5,20] 为0xffff,所以就是拷贝的 0xffff << 16 0xffff0000 |
高四16进制位全F:(0xi | 0xFFFF0000) {i取值 [1-0xffff]} |
mov w0, #0xffffffff | 0x12800000 0x129 |
hw位bit[21,22]为00b,表示不左移,bit[5,20] 为0,所以就是拷贝的 ~(0 ) = 0xffffffff |
低四16进制位全F:(0xi0000 | 0xFFFF) {i取值 [1-0xfffe]} |
movn w0,#0x1ffff | 0x12bfffc0 0x12a |
hw位bit[21,22]为01b,表示左移16bit,bit[5,20] 为0xfffe,所以就是拷贝的 ~(0xfffe<< 16 ) = ~0xfffe0000 = 0x1ffff; |
/* 当前接口仅支持大端armv8 ,其余未验证 */ UINT32 will_return_to_arm_asm(int iData, unsigned char *pcAsm) { int iDataTmp = 0; UCHAR *pcRetAsm = NULL; /* ARM机器码的阅读和在内存中的存储是相反的 */ /*将函数代码段替换为以下内容,实现直接修改函数返回值*/ /* 52800140 mov w0, #0xa // #10 d65f03c0 ret */ Bsp_Printf("iData:0x%x\n", iData); pcRetAsm = &(pcAsm[8]); ARM_RET_CMD(pcRetAsm); /* 高16位全0 1: 0x52800020 */ if (0 == (iData & 0xFFFF0000)) { Bsp_Printf("1: iData:0x%x\n", iData); pcAsm[0] = (iData << 5) & 0xFF; pcAsm[1] = (iData >> 3) & 0xFF; pcAsm[2] = (iData >> 11) | 0x80; pcAsm[3] = ARM_MOVZ_CMD; } /* 低16位全0 0x10000 : 0x52b00020 */ else if (0 == (iData & 0xFFFF)) { iDataTmp = (iData >> 16) & 0xFFFF;//右移16 Bsp_Printf("2: iDataTmp:0x%x\n", iDataTmp); pcAsm[0] = (iDataTmp << 5) & 0xFF; pcAsm[1] = (iDataTmp >> 3) & 0xFF; pcAsm[2] = (iDataTmp >> 11) | 0xA0;//左移16 pcAsm[3] = ARM_MOVZ_CMD; } /* 高16位全1 */ else if (0xFFFF0000 == (iData & 0xFFFF0000)) { iDataTmp = ~iData;//按位取反 Bsp_Printf("3: iDataTmp:0x%x\n", iDataTmp); pcAsm[0] = (iDataTmp << 5) & 0xFF; pcAsm[1] = (iDataTmp >> 3) & 0xFF; pcAsm[2] = (iDataTmp >> 11) | 0x80; pcAsm[3] = ARM_MOVN_CMD; } /* 低16位全1 */ else if (0xFFFF == (iData & 0xFFFF)) { iDataTmp = ((~iData) >> 16) & 0xFFFF;//按位取反,右移16 Bsp_Printf("4: iDataTmp:0x%x\n", iDataTmp); pcAsm[0] = (iDataTmp << 5) & 0xFF; pcAsm[1] = (iDataTmp >> 3) & 0xFF; pcAsm[2] = (iDataTmp >> 11) | 0xA0;//左移16 pcAsm[3] = ARM_MOVN_CMD; } else { Bsp_Printf("no support ! iData:0x%x\n", iData); return BSP_ERROR; } return BSP_OK; }
总结:ARM V8能用单条指令来进行赋值操作的立即数 需要是以下四种:
高四16进制位为全0/全F ;低四16进制位全0/全F
分析发现无法支持非法立即数的返回操作,能否把所有数据都按照4条指令来完成赋值,如下图 立即数:0x1234567890123456 (64bit)
movk 与movz区别是,movz会清除其它位,movk保留
需要考虑修改20字节的话会不会操作到其它函数,也就是说被打桩函数大小需要超过5条指令,反汇编发现只有一个retrun 的函数,指令也是 12条
还需要考虑进修改此页能不能包含20字节修改,否则会失败,如下图,当修改函数CmdkBttlReparserHwCntGet 时
因为CmdkBttlReparserHwCntGet 函数地址位0xffff7cc0dff4 + 20 = 0xFFFF7CC0E008 超过了 0xFFFF7CC0D000 0xFFFF7CC0DFFF 这个页范围,需要修改两个页的内存属性
修改后: