LXR | KVM | PM | Time | Interrupt | Systems Performance | Bootup Optimization

ARM指令和机器码对应关系:动态生成可执行指令

汇编经过编译器生成机器可以执行的机器码。由于有一段指令需要动态生成,所以简单看了一下汇编和机器码之间的关系。做了记录方便后面查找。

大部分情况下,写C/ASM,经由工具链生成可执行机器码。所以主要功能先由C/ASM编写,然后根据需求改变部分机器码。

首先研究一下《Instruction Set Assembly Guide for Armv7 and earlier Arm® architectures Version 2.0 Reference Guide》和《Arm A-profile A32/T32 Instruction Set Architecture》。

1. Conditional instruction

A32每条指令的bit[31:28]表示需要满足的条件,以PSTATE.NZCV作为输入检查条件是否满足。

// ConditionHolds()
// ================
// Return TRUE iff COND currently holds--如果当前条件满足,返回TRUE。
boolean ConditionHolds(bits(4) cond)
  // Evaluate base condition.
  boolean result;
  case cond<3:1> of--根据cond[3:1]以及PSTATE返回result的值。
    when '000' result = (PSTATE.Z == '1'); // EQ or NE
    when '001' result = (PSTATE.C == '1'); // CS or CC
    when '010' result = (PSTATE.N == '1'); // MI or PL
    when '011' result = (PSTATE.V == '1'); // VS or VC
    when '100' result = (PSTATE.C == '1' && PSTATE.Z == '0'); // HI or LS
    when '101' result = (PSTATE.N == PSTATE.V); // GE or LT
    when '110' result = (PSTATE.N == PSTATE.V && PSTATE.Z == '0'); // GT or LE
    when '111' result = TRUE; // AL
  // Condition flag values in the set '111x' indicate always true
  // Otherwise, invert condition if necessary.
  if cond<0> == '1' && cond != '1111' then--如果cond[0]=1,或者cond[3:0]!=1111,则result取反。
    result = !result;
return result;

所以不同的cond[3:0]检查的不同的PSTATE.NZCV标志位,结合Condition code suffixes对应关系如下:

 cond[3:0 PSTATE   Suffix Meaning
0000 PSTATE.Z == '1' EQ Equal
0001 !(PSTATE.Z == '1') NE  Not equal
0010 PSTATE.C == '1' CS  Carry set(identical to HS)
0011 !(PSTATE.C == '1') CC  Cary clear(identical to LO)
0100 PSTATE.N == '1'   MI  Minus or negative result
0101 !(PSTATE.N == '1' ) PL  Positive or zero result
0110 PSTATE.V == '1'   VS  Overflow
0111 !(PSTATE.V == '1'  ) VC  No overflow
1000 PSTATE.C == '1' && PSTATE.Z == '0' HI  Unsigned higher
1001 !(PSTATE.C == '1' && PSTATE.Z == '0') LS  Unsigned lower or same
1010 PSTATE.N == PSTATE.V GE  Signed greater than or equal
1011 !(PSTATE.N == PSTATE.V) LT  Signed less than
1100 (PSTATE.N == PSTATE.V) && PSTATE.Z == '0' GT  Signed greater than
1101 !((PSTATE.N == PSTATE.V) && PSTATE.Z == '0') LE  Signed len than or equal
1110 TRUE   AL  Alaways(this is the default)
1111 TRUE AL  Alaways(this is the default)

以blx为例,如何从blx对应到机器码

BLX (register)是无条件跳转到(register)指向的地址。其指令机器码为:

 其中cond[3:0]=1110,所以blx (register)的bit[31:4] = 1110 0001 0010 1111 1111 1111 0011,bit[3:0]为寄存器序号,从0~15。其中r15即为pc寄存器,结果不可预测

所以blx r3的机器码即为0xE12FFF30 | 0x3 = 0xE12FFF33

设置跳转地址到寄存器,然后跳转到地址。

如果要对如下指令,使用不固定寄存器跳转到不固定地址:

mov r3, #0x0
movt r3, #0x8000
blx r3

编译后的机器码为:

根据MOV指令机器码说明,这里对应A1 S==0的情形。如果是imm16则对应A2机器码。

所以mov r3, #0x0的机器码为0xE3A00(cond+S+...)3(Rd)000(imm12) = 0xE3A03000。

如果是mov r3, #0xffff,机器码则为0xE30(cond...)+F(imm4)+3(Rd)+FFF(imm12) = 0xE30F3FFF

 movt改变寄存器的高16位数值,所以movt r3, #0x8000对应的机器码即为:0xE34(cond...)8(imm4)3(Rd)000(imm12) = 0xE3883000

 所以可以通过任意寄存器跳转到任意地址生成机器码。

void update_instructions(unsigned int addr, unsigned int reg, unsigned int *instructions)
{ unsigned
int * intr p = instructions;
if(reg >= 15) { return;
} //mov r3,#0x0
if(addr
& 0x0000F000) {
*intr p++ = 0xE3A00000 \
|
(addr & 0x0000F000) << 4 \
|(reg << 12) \
|(addr & 0x00000FFF);
} else {
*intr _p++ = 0xE3000000 \
|
(reg << 12) \
|(addr & 0x00000FFF);
}
//movt r3,#0x8000
*intr p++ = 0xE3400000 \ |(addr & 0xF0000000) >> 12 \ |(reg << 12) \
|(addr & 0x0FFF0000) >> 16; //blx r3
*intr p = 0xE12FFF30 |reg;
}

 

为什么blx label地址范围+/-32MB,而blx <reg>不受限制

从blx (immediate)的机器码可知,imm24被扩展到Signed 26位,所以blx (immediate)的跳转空间是64MB,在当前指令位置的前后32MB内。

而blx <reg>跳转的地址存于寄存器中,寄存器的位宽足够覆盖整个地址空间。

posted on 2023-07-10 23:59  ArnoldLu  阅读(407)  评论(0编辑  收藏  举报

导航