Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Explicitly call __remill_undef for undefined arith flags. #543

Merged
merged 5 commits into from
Sep 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion lib/Arch/Arch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -688,14 +688,23 @@ const Register *Arch::AddRegister(const char *reg_name_, llvm::Type *val_type,
const_cast<Register *>(reg->parent)->children.push_back(reg);
}

auto maybe_get_reg_name = [](auto reg_ptr) -> std::string {
if (!reg_ptr) {
return "(nullptr)";
}
return reg_ptr->name;
};

// Provide easy access to registers at specific offsets in the `State`
// structure.
for (auto i = reg->offset; i < (reg->offset + reg->size); ++i) {
auto &reg_at_offset = impl->reg_by_offset[i];
if (!reg_at_offset) {
reg_at_offset = reg;
} else if (reg_at_offset) {
CHECK_EQ(reg_at_offset->EnclosingRegister(), reg->EnclosingRegister());
CHECK_EQ(reg_at_offset->EnclosingRegister(), reg->EnclosingRegister())
<< maybe_get_reg_name(reg_at_offset->EnclosingRegister()) << " != "
<< maybe_get_reg_name(reg->EnclosingRegister());;
reg_at_offset = reg;
}
}
Expand Down
4 changes: 2 additions & 2 deletions lib/Arch/X86/Arch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -467,9 +467,9 @@ static void DecodeMemory(Instruction &inst, const xed_decoded_inst_t *xedd,
auto segment_reg = ignore_segment(deduce_segment(raw_segment_reg));

// Special case: `POP [xSP + ...] uses the value of `xSP` after incrementing
// it by the stack width.
// it by the stack width. For more reasoning see definition of semantics for POP.
if (XED_ICLASS_POP == iclass && XED_REG_RSP == base_wide) {
disp += static_cast<int64_t>(size / 8);
inst.function = "POP_MEM_XSP_" + std::to_string(size);
}

Operand op = {};
Expand Down
4 changes: 2 additions & 2 deletions lib/Arch/X86/Semantics/BINARY.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,10 +248,10 @@ ALWAYS_INLINE static void WriteFlagsMul(State &state, T lhs, T rhs, U res,
V res_trunc) {
const auto new_of = Overflow<tag_mul>::Flag(lhs, rhs, res);
FLAG_CF = new_of;
FLAG_PF = ParityFlag(res); // Technically undefined.
FLAG_PF = BUndefined(); // Technically undefined.
FLAG_AF = BUndefined();
FLAG_ZF = BUndefined();
FLAG_SF = std::is_signed<T>::value ? SignFlag(res_trunc) : BUndefined();
FLAG_SF = BUndefined();
FLAG_OF = new_of;
}

Expand Down
36 changes: 28 additions & 8 deletions lib/Arch/X86/Semantics/BITBYTE.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,12 +148,23 @@ DEF_ISEL(SETBE_GPR8) = SETBE<R8W>;

namespace {


#define _BTClearUndefFlags() \
do { \
UndefFlag(of); \
UndefFlag(sf); \
UndefFlag(zf); \
UndefFlag(af); \
UndefFlag(pf); \
} while (false)

template <typename S1, typename S2>
DEF_SEM(BTreg, S1 src1, S2 src2) {
auto val = Read(src1);
auto bit = ZExtTo<S1>(Read(src2));
auto bit_mask = UShl(Literal<S1>(1), URem(bit, BitSizeOf(src1)));
Write(FLAG_CF, UCmpNeq(UAnd(val, bit_mask), Literal<S1>(0)));
_BTClearUndefFlags();
return memory;
}

Expand All @@ -164,6 +175,7 @@ DEF_SEM(BTmem, S1 src1, S2 src2) {
auto index = UDiv(bit, BitSizeOf(src1));
auto val = Read(GetElementPtr(src1, index));
Write(FLAG_CF, UCmpNeq(UAnd(val, bit_mask), Literal<S1>(0)));
_BTClearUndefFlags();
return memory;
}

Expand All @@ -174,6 +186,7 @@ DEF_SEM(BTSreg, D dst, S1 src1, S2 src2) {
auto bit_mask = UShl(Literal<S1>(1), URem(bit, BitSizeOf(val)));
WriteZExt(dst, UOr(val, bit_mask));
Write(FLAG_CF, UCmpNeq(UAnd(val, bit_mask), Literal<S1>(0)));
_BTClearUndefFlags();
return memory;
}

Expand All @@ -185,6 +198,7 @@ DEF_SEM(BTSmem, D dst, S1 src1, S2 src2) {
auto val = Read(GetElementPtr(src1, index));
Write(GetElementPtr(dst, index), UOr(val, bit_mask));
Write(FLAG_CF, UCmpNeq(UAnd(val, bit_mask), Literal<S1>(0)));
_BTClearUndefFlags();
return memory;
}

Expand All @@ -195,6 +209,7 @@ DEF_SEM(BTRreg, D dst, S1 src1, S2 src2) {
auto bit_mask = UShl(Literal<S1>(1), URem(bit, BitSizeOf(src1)));
WriteZExt(dst, UAnd(val, UNot(bit_mask)));
Write(FLAG_CF, UCmpNeq(UAnd(val, bit_mask), Literal<S1>(0)));
_BTClearUndefFlags();
return memory;
}

Expand All @@ -206,6 +221,7 @@ DEF_SEM(BTRmem, D dst, S1 src1, S2 src2) {
auto val = Read(GetElementPtr(src1, index));
Write(GetElementPtr(dst, index), UAnd(val, UNot(bit_mask)));
Write(FLAG_CF, UCmpNeq(UAnd(val, bit_mask), Literal<S1>(0)));
_BTClearUndefFlags();
return memory;
}

Expand All @@ -216,6 +232,7 @@ DEF_SEM(BTCreg, D dst, S1 src1, S2 src2) {
auto bit_mask = UShl(Literal<S1>(1), URem(bit, BitSizeOf(val)));
WriteZExt(dst, UXor(val, bit_mask));
Write(FLAG_CF, UCmpNeq(UAnd(val, bit_mask), Literal<S1>(0)));
_BTClearUndefFlags();
return memory;
}

Expand All @@ -227,9 +244,12 @@ DEF_SEM(BTCmem, D dst, S1 src1, S2 src2) {
auto val = Read(GetElementPtr(src1, index));
Write(GetElementPtr(dst, index), UXor(val, bit_mask));
Write(FLAG_CF, UCmpNeq(UAnd(val, bit_mask), Literal<S1>(0)));
_BTClearUndefFlags();
return memory;
}

#undef _BTClearUndefFlags

} // namespace

DEF_ISEL_Mn_In(BT_MEMv_IMMb, BTmem);
Expand Down Expand Up @@ -323,11 +343,11 @@ DEF_SEM(BSR, D dst, S src) {
auto index = USub(USub(BitSizeOf(src), count), Literal<S>(1));
Write(FLAG_ZF, ZeroFlag(val));
auto index_ret = Select(FLAG_ZF, Read(dst), ZExtTo<D>(index));
Write(FLAG_OF, false); // Undefined, but experimentally 0.
Write(FLAG_SF, false); // Undefined, but experimentally 0.
Write(FLAG_OF, BUndefined()); // Undefined, but experimentally 0.
Write(FLAG_SF, BUndefined()); // Undefined, but experimentally 0.
Write(FLAG_PF, ParityFlag(index)); // Undefined, but experimentally 1.
Write(FLAG_AF, false); // Undefined, but experimentally 0.
Write(FLAG_CF, false); // Undefined, but experimentally 0.
Write(FLAG_AF, BUndefined()); // Undefined, but experimentally 0.
Write(FLAG_CF, BUndefined()); // Undefined, but experimentally 0.
Write(dst, index_ret);
return memory;
}
Expand All @@ -337,11 +357,11 @@ DEF_SEM(BSF, D dst, S src) {
auto val = Read(src);
Write(FLAG_ZF, ZeroFlag(val));
auto index = Select(FLAG_ZF, Read(dst), ZExtTo<D>(CountTrailingZeros(val)));
Write(FLAG_OF, false); // Undefined, but experimentally 0.
Write(FLAG_SF, false); // Undefined, but experimentally 0.
Write(FLAG_OF, BUndefined()); // Undefined, but experimentally 0.
Write(FLAG_SF, BUndefined()); // Undefined, but experimentally 0.
Write(FLAG_PF, ParityFlag(index));
Write(FLAG_AF, false); // Undefined, but experimentally 0.
Write(FLAG_CF, false); // Undefined, but experimentally 0.
Write(FLAG_AF, BUndefined()); // Undefined, but experimentally 0.
Write(FLAG_CF, BUndefined()); // Undefined, but experimentally 0.
Write(dst, index);
return memory;
}
Expand Down
2 changes: 2 additions & 0 deletions lib/Arch/X86/Semantics/FLAGS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,8 @@ struct Carry<tag_sub> {

} // namespace

#define UndefFlag(name) do { state.aflag.name = __remill_undefined_8(); } while (false)

#define ClearArithFlags() \
do { \
state.aflag.cf = __remill_undefined_8(); \
Expand Down
3 changes: 3 additions & 0 deletions lib/Arch/X86/Semantics/LOGICAL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ DEF_SEM(OR, D dst, S1 src1, S2 src2) {
auto res = UOr(lhs, rhs);
WriteZExt(dst, res);
SetFlagsLogical(state, lhs, rhs, res);
UndefFlag(af);
return memory;
}

Expand All @@ -55,6 +56,7 @@ DEF_SEM(XOR, D dst, S1 src1, S2 src2) {
auto res = UXor(lhs, rhs);
WriteZExt(dst, res);
SetFlagsLogical(state, lhs, rhs, res);
UndefFlag(af);
return memory;
}

Expand All @@ -70,6 +72,7 @@ DEF_SEM(TEST, S1 src1, S2 src2) {
auto rhs = Read(src2);
auto res = UAnd(lhs, rhs);
SetFlagsLogical(state, lhs, rhs, res);
UndefFlag(af);
return memory;
}

Expand Down
19 changes: 19 additions & 0 deletions lib/Arch/X86/Semantics/POP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,22 @@ DEF_SEM(POP, D dst) {
return memory;
}

template<typename D>
DEF_SEM(POP_MEM_XSP, D dst) {
addr_t op_size = ZExtTo<D>(ByteSizeOf(dst));
addr_t old_xsp = Read(REG_XSP);
addr_t new_xsp = UAdd(old_xsp, op_size);

// `XSP` will be adjusted by `op_size`. Unfortunately, `dst` at this point
// no longer has any information about the fact it was composed of `XPS`.
// This semantic is a special case of general `POP` and it makes sure that
// the adjustment happens correctly.
// See #PR for more details.
Write(REG_XSP, new_xsp);
WriteZExt(D{dst.addr + op_size}, Read(ReadPtr<D>(old_xsp _IF_32BIT(REG_SS_BASE))));
return memory;
}

#if 32 == ADDRESS_SIZE_BITS
DEF_SEM(DoPOPA) {
Write(REG_DI, PopFromStack<uint16_t>(memory, state));
Expand Down Expand Up @@ -123,6 +139,9 @@ DEF_ISEL(POP_GPRv_58_16) = POP<R16W>;
DEF_ISEL_R32or64W(POP_GPRv_51, POP);
DEF_ISEL_R32or64W(POP_GPRv_58, POP);

DEF_ISEL(POP_MEM_XSP_16) = POP_MEM_XSP<M16W>;
DEF_ISEL_M32or64W(POP_MEM_XSP, POP_MEM_XSP);

DEF_ISEL(POP_MEMv_16) = POP<M16W>;
DEF_ISEL_M32or64W(POP_MEMv, POP);

Expand Down
25 changes: 18 additions & 7 deletions lib/Arch/X86/Semantics/ROTATE.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@ DEF_SEM(ROL, D dst, S1 src1, S2 src2) {
Write(FLAG_CF, UCmpEq(UAnd(new_val, one), one));
if (1 == temp_count) {
Write(FLAG_OF, BXor(FLAG_CF, SignFlag(new_val)));
// OF undefined for `1 != temp_count`.
} else {
Write(FLAG_OF, false);
Write(FLAG_OF, BUndefined());
}
// OF undefined for `1 == temp_count`.
} else {
WriteZExt(dst, val);
}
Expand All @@ -62,9 +62,12 @@ DEF_SEM(ROR, D dst, S1 src1, S2 src2) {
UOr(UShr(val, temp_count), UShl(val, USub(op_size, temp_count)));
WriteZExt(dst, new_val);
Write(FLAG_CF, SignFlag(new_val));
Write(FLAG_OF, BXor(FLAG_CF, SignFlag(UShl(new_val, one))));
// OF undefined for `1 != temp_count`.
if (temp_count == 1)
Write(FLAG_OF, BXor(FLAG_CF, SignFlag(UShl(new_val, one))));
else
Write(FLAG_OF, BUndefined());

// OF undefined for `1 == temp_count`.
} else {
WriteZExt(dst, val);
}
Expand Down Expand Up @@ -146,9 +149,13 @@ DEF_SEM(RCL, D dst, S1 src1, S2 src2) {
UShr(right, one));
WriteZExt(dst, new_val);
Write(FLAG_CF, SignFlag(UShl(val, USub(temp_count, one))));
Write(FLAG_OF, BXor(FLAG_CF, SignFlag(new_val)));
// OF undefined for `1 != temp_count`.
if (temp_count == 1) {
Write(FLAG_OF, BXor(FLAG_CF, SignFlag(new_val)));
} else {
Write(FLAG_OF, BUndefined());
}

// OF undefined for `1 == temp_count`.
} else {
WriteZExt(dst, val);
}
Expand Down Expand Up @@ -180,7 +187,11 @@ DEF_SEM(RCR, D dst, S1 src1, S2 src2) {
UShl(right, one));
WriteZExt(dst, new_val);
Write(FLAG_CF, UCmpNeq(UAnd(left, one), zero));
Write(FLAG_OF, BXor(SignFlag(UShl(new_val, one)), SignFlag(new_val)));
if (temp_count == 1) {
Write(FLAG_OF, BXor(SignFlag(UShl(new_val, one)), SignFlag(new_val)));
} else {
Write(FLAG_OF, BUndefined());
}

// OF undefined for `1 == temp_count`.
} else {
Expand Down
5 changes: 3 additions & 2 deletions lib/Arch/X86/Semantics/SHIFT.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,15 +148,16 @@ DEF_SEM(SHL, D dst, S1 src1, S2 src2) {
new_val = UShl(res, 1);

} else {
new_of = 1; // Undefined, probably 1.
new_of = BUndefined(); // Undefined, probably 1.
// TODO(lukas): Double check.
new_cf = 0; // Undefined, probably 0.
new_val = 0;
}

WriteZExt(dst, new_val);
Write(FLAG_CF, new_cf);
Write(FLAG_PF, ParityFlag(new_val));
Write(FLAG_AF, false); // Undefined, experimentally 0.
Write(FLAG_AF, BUndefined()); // Undefined, experimentally 0.
Write(FLAG_ZF, ZeroFlag(new_val));
Write(FLAG_SF, SignFlag(new_val));
Write(FLAG_OF, new_of);
Expand Down
9 changes: 9 additions & 0 deletions tests/X86/BITBYTE/BT.S
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

TEST_BEGIN(BTr16i8, 1)
TEST_IGNORE_FLAGS(SF ZF AF PF OF)
TEST_INPUTS(
0,
1)
Expand All @@ -23,6 +24,7 @@ TEST_INPUTS(
TEST_END

TEST_BEGIN(BTr16r16, 2)
TEST_IGNORE_FLAGS(SF ZF AF PF OF)
TEST_INPUTS(
0, 0,
1, 0,
Expand All @@ -34,6 +36,7 @@ TEST_INPUTS(
TEST_END

TEST_BEGIN(BTr32i8, 1)
TEST_IGNORE_FLAGS(OF SF ZF AF PF)
TEST_INPUTS(
0,
1)
Expand All @@ -42,6 +45,7 @@ TEST_INPUTS(
TEST_END

TEST_BEGIN(BTr32r32, 2)
TEST_IGNORE_FLAGS(OF SF ZF AF PF)
TEST_INPUTS(
0, 0,
1, 0,
Expand All @@ -56,6 +60,7 @@ TEST_INPUTS(
TEST_END

TEST_BEGIN_64(BTr32i8_64, 1)
TEST_IGNORE_FLAGS(OF SF ZF AF PF)
TEST_INPUTS(
0,
1)
Expand All @@ -64,6 +69,7 @@ TEST_INPUTS(
TEST_END_64

TEST_BEGIN_64(BTr64r64_64, 2)
TEST_IGNORE_FLAGS(OF SF ZF AF PF)
TEST_INPUTS(
0, 0,
1, 0,
Expand All @@ -81,6 +87,7 @@ TEST_INPUTS(
TEST_END_64

TEST_BEGIN_64(BTm16r16, 1)
TEST_IGNORE_FLAGS(OF SF ZF AF PF)
TEST_INPUTS(
0,
1,
Expand All @@ -96,6 +103,7 @@ TEST_INPUTS(
TEST_END_64

TEST_BEGIN_64(BTm32r32, 1)
TEST_IGNORE_FLAGS(OF SF ZF AF PF)
TEST_INPUTS(
0,
1,
Expand All @@ -111,6 +119,7 @@ TEST_INPUTS(
TEST_END_64

TEST_BEGIN_64(BTm64r64_64, 1)
TEST_IGNORE_FLAGS(OF SF ZF AF PF)
TEST_INPUTS(
0,
1,
Expand Down
Loading