Closed hidde-jan closed 5 years ago
I'm not sure about SUBC. It might also have a wrong check. It might need to be changed to
dst >= (src + self.get_carry())
I'm kinda confused. This is the behavior I saw in the microcorruptions emulator for SUBC:
sr = 0, r15 = 1
subc #0x1, r15
=> sr = 3 (C+Z), r15 = 0
And
sr = 1 (C), r15 = 1
subc #0x1, r15
=> sr = 1 (C), r15 = 1
And
sr = 1 (C), r15 = 0
subc #0x1, r15
=> sr = 2 (Z), r15 = 0
I'm not sure what the carry logic is here now.
I think that microcorruption's emulation of the subc instruction is wrong, so I'd stick to the docs. For example, take the following case:
r7 = 7
sr = 1
...
-> sub #0x2, r7
...
Microcorruption claims that the value of r7
afterward is 6.
However, if we look at the TI's documentation, subc is defined as (~src) + C + dst -> dst
. This gives us (~2) + 1 + 7 = (-3) + 1 + 7 = 5
.
Yeah, I think you're right. I'm pretty sure about the change in this PR though, as it only touches SUB.
Though it does also appear that the two "equivalent" definitions in the docs don't match:
(~src) + C + dst -> dst
: (~2) + 1 + 7 = (-3) + 1 + 7 = 5
dst - (src - 1) + C -> dst
: 7 - (2 - 1) + 1 = 7 - 1 + 1 = 7
From http://www.ti.com/lit/ug/slau049f/slau049f.pdf:
dst + .NOT.src + C −> dst
or
(dst − src − 1 + C −> dst)
So it would be
7 - 2 - 1 + 1 = 7 - 3 + 1 = 5
Yeah, that difference only appears in the 5xx and 6xx family guide, so I think we can assume the second definition on that generation's docs is wrong
So we should be able to use the carry flag as dst >= src + 1 - c
If you agree, add that in to the PR and then I'll merge (and, if you feel up to it, fix the completely incorrect definition of subc's compute_results)
I’ll do a quick check tomorrow. Off to bed now 😴
Op 3 mrt. 2019 om 21:45 heeft lockshaw notifications@github.com het volgende geschreven:
If you agree, add that in to the PR and then I'll merge
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or mute the thread.
I think I got it now. After getting 4 people confused over the language in the TI MSP430 guide, I've reimplemented SUB and SUBC as it actually works in the microcontroller (SUB is ADD with ~src+1 and SUBC is ADD with ~src+C).
The overflow is now relatively easy to check. For ADD(C) it's
pos + pos = neg
or
neg + neg = pos
For SUB(C) it's
pos - neg = neg
or
neg - pos = pos
This is consistent with the documentation. The carry bit is more difficult. In the docs, it consistently says it's implemented by performing the operation and then checking if there is a carry out from the Most Significant Bit.
Indeed, with the new implementation we have
r15 = 0xffff
sub #1, r15
=> r15 = 0xfffe, sr = 1 (C)
i.e.
0xffff
+ ~0x0001
+ 0x0001
----------
0xffff
+ 0xfffe
+ 0x0001
----------
0x1fffd
+ 0x0001
----------
0x1fffe
=> r15 = 0xfffe, sr = 1 (C)
You can also work this out for sub #0xffff, r15
and we still get a carry, which is consistent with the previous check dst >= src
.
Hold on, I think there's still a mistake somewhere.
Another update. I saw that the IRSB got ~20% more steps/instruction due to all the casting and negating in the previous commit. I've now cleaned up ADD(C) and changed SUB(C). SUBC's carry logic needs a few casts to Type.int_17 since we can get an overflow. For instance:
r15 = 0, sr = 0
subc #0xffff, r15
----------------
0x0000
- 0x0000
+ 0x0000
----------------
0x0000
=> r15 = 0, sr = 0
has no carry, but if we don't cast to int17, we get 0xffff + 0x1 - 0x0 = 0x0 =< 0x0
so the carry flag would have been set erroneously.
Ok, I'm done. I'm sure the current behavior for the carry flag of SUBC is now correct. What I'm less sure about is if this behavior is equivalent to the previous behavior where we cast up to int17 and then do the >=
.
I notice the new builds are failing due to flake warnings. Do you need me to clean some of those up before the merge?
Looks good! Just make those couple minor fixes and I'll merge it in.
Ok, updated the PR
When running angr alongside microcorruptions, I noticed the carry bit was not always set correctly on SUB, CMP and TST.
From wikipedia:
It seems the current carry check is not correct.