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:
Yuvraj Saxena 2023-03-19 17:38:25 +05:30 committed by GitHub
parent d28be65647
commit 9ad89fd980
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 22 additions and 20 deletions

View File

@ -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;
}

View File

@ -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