Fix tb instruction for ARM assembler ##asm
Current code unconditionally drops last 2 bits without checking if those 2 bits are set or cleared, if ignored these 2 bits are eventually lost and not encoded in machine instruction and it's dangerous to assume destination supplied is valid to correct this I implemented a check. Last 2 bits are discarded when final machine instruction is generated and later in the decode phase this 14 bit immediate value (destination) is shifted left 2 bit positions, and later sign extended to 64 bits that means we can actually encode a number with 16 bits but current code encodes only upto 14 bits. Thus, wasting 2 bits. Also, Current code unconditionally parses last 5 bits from immediate 1, which is nothing but bit number to be tested in the register. Therefore, it must be within range 0-31 if 32 bit register is used, range must 0-63 if 64 bit register is used. Also, in the case of 64 bit register only last 5 bits are encoded because it's later concatenated with MSB hence rendering a 6 bit number that can be used to denote bit positions between 0-63. To tackle this a check for this is implemented. At last testcases are added to demonstrate these checks.
This commit is contained in:
parent
d28be65647
commit
9ad89fd980
|
@ -837,29 +837,30 @@ static ut32 tb(ArmOp *op) {
|
|||
} else {
|
||||
return UT32_MAX;
|
||||
}
|
||||
if (reg64_imm) {
|
||||
if (op->operands[1].immediate > 0x3f) {
|
||||
R_LOG_ERROR("Bit to be tested must be in range 0-63 for %s", op->mnemonic);
|
||||
return UT32_MAX;
|
||||
}
|
||||
} else if (reg32_imm) {
|
||||
if (op->operands[1].immediate > 0x1f) {
|
||||
R_LOG_ERROR("Bit to be tested must be in range 0-31 for %s", op->mnemonic);
|
||||
return UT32_MAX;
|
||||
}
|
||||
}
|
||||
ut64 dst = op->operands[2].immediate;
|
||||
st64 delta = dst - op->addr;
|
||||
ut64 maxis = R_ABS (delta);
|
||||
if (maxis > 0x7fff) {
|
||||
R_LOG_ERROR ("tbz destination is too far");
|
||||
if ((delta & 3) || maxis > 0xfffc) {
|
||||
R_LOG_ERROR ("invalid destination for %s", op->mnemonic);
|
||||
return UT32_MAX;
|
||||
}
|
||||
data = k;
|
||||
#if 0
|
||||
data |= (op->operands[0].reg & 0x1f) << 24;
|
||||
data |= (op->operands[1].immediate & 0x1f) << 11;
|
||||
data |= (op->operands[2].immediate & 0x1c) << 27;
|
||||
data |= (op->operands[2].immediate & 0x1fe0) << 11;
|
||||
data |= (op->operands[2].immediate & 0x1fe000) >> 5;
|
||||
#else
|
||||
data |= (op->operands[0].reg & 0x1f) << 24;
|
||||
data |= (op->operands[1].immediate & 0x1f) << 11;
|
||||
data |= (delta & 0x1c) << 27;
|
||||
data |= (delta & 0x1fe0) << 11;
|
||||
// data |= (delta & 0xfe000) >> 5;
|
||||
data |= ((delta >> 12) & 3) << 7;
|
||||
//data |= (delta & 0x1fe0) << 11;
|
||||
#endif
|
||||
data |= ((delta >> 13) & 7) << 8;
|
||||
return data;
|
||||
}
|
||||
|
||||
|
|
|
@ -635,13 +635,14 @@ ad "rev32 x15, x25" 2F0BC0DA
|
|||
ad "rev32 x5, x11" 6509C0DA
|
||||
ad "rev32 x1, x2" 4108C0DA
|
||||
ad "rev32 x10, x16" 0A0AC0DA
|
||||
ad "tbz x1, 0x20, 0x1234" a19100b6
|
||||
ad "tbnz x1, 0x20, 0x1234" a19100b7
|
||||
# ad "tbz x1, 0, 0x1234" a19100b6 INVALID?
|
||||
# ad "tbnz x1, 0, 0x1234" a19100b7 INVALID?
|
||||
# ad "tbz w0, 0, 0x1234" 9dfe80b7
|
||||
# ad "tbz w1, 0, 0x1234" 9dfe80b7
|
||||
# ad "tbz w2, 2, 0x4321" 1dff80b6
|
||||
adB "tbz x1, 0x1f, 0x3" e1ffffb6
|
||||
adB "tbnz x1, 0x1f, 0x3" e1ffffb7
|
||||
adB "tbz w1, 0x1f, 0x3" e1ffff36
|
||||
adB "tbnz w1, 0x1f, 0x3" e1ffff37
|
||||
adB "tbz w0, 0x20, 0xc" 60000036
|
||||
adB "tbnz w0, 0x20, 0xc" 60000037
|
||||
adB "tbz x0, 0x40, 0xc" 600000b6
|
||||
adB "tbnz x0, 0x40, 0xc" 600000b7
|
||||
ad "tbz x30, 0x3f, 0x1c" FE00F8B6
|
||||
ad "tbz x5, 0x27, 0x14" A50038B6
|
||||
ad "tbz x29, 0x30, 0x1fe0" 1DFF80B6
|
||||
|
|
Loading…
Reference in New Issue