Reputation: 33
I am currently trying to understand how does the movw instruction work on ARM, to be able to hex edit a library and change a value that is being set with said instruction.
The library presents code as follows (output from objdump):
[...]
29c4: f44f 71f0 mov.w r1, #480 ; 0x1e0
[...]
What I'm trying to do in other words, is figure out how is 0x1e0 / 480 represented inside "f44f 71f0". I've been reading stuff around the net, including http://blogs.arm.com/software-enablement/251-how-to-load-constants-in-assembly-for-arm-architecture/ and I think I understand how does movw work and it's limitations; but I still don't get how does the value shown on the instruction map to the actual binary code. Any documentation or insignt you might be able to provide on the matter is much appreciated :)
Upvotes: 3
Views: 4868
Reputation: 605
Here's MOV T2 encoding (from ARM Architecture Reference Manual)
11110 i 0 0010 S 1111 0 imm3 rd imm8
d = UInt(Rd);
setflags = (S == ‘1’);
(imm32, carry) = ThumbExpandImm_C(i:imm3:imm8, APSR.C);
if d IN {13,15} then UNPREDICTABLE;
Because your pattern is
i S imm3 rd imm8
11110 1 0 0010 0 1111 0 111 0001 11110000
You have i=1, S=0, imm3=111, imm8=11110000
By checking what ThumbExpandImm_C() does, you will understand how the values became 0x1e0
// ThumbExpandImm_C()
// ==================
(bits(32), bit) ThumbExpandImm_C(bits(12) imm12, bit carry_in)
if imm12<11:10> == ‘00’ then
case imm12<9:8> of
when ‘00’
imm32 = ZeroExtend(imm12<7:0>, 32);
when ‘01’
if imm12<7:0> == ‘00000000’ then UNPREDICTABLE;
imm32 = ‘00000000’ : imm12<7:0> : ‘00000000’ : imm12<7:0>;
when ‘10’
if imm12<7:0> == ‘00000000’ then UNPREDICTABLE;
imm32 = imm12<7:0> : ‘00000000’ : imm12<7:0> : ‘00000000’;
when ‘11’
if imm12<7:0> == ‘00000000’ then UNPREDICTABLE;
imm32 = imm12<7:0> : imm12<7:0> : imm12<7:0> : imm12<7:0>;
carry_out = carry_in;
else
unrotated_value = ZeroExtend(‘1’:imm12<6:0>, 32); <--- a
(imm32, carry_out) = ROR_C(unrotated_value, UInt(imm12<11:7>)); <--- b
return (imm32, carry_out);
Our imm12 = i:imm3:imm8 (1:111:11110000) = 1111 1111 0000
Our values will pass lines (a) and (b) because highest 2 bits [11,10] are '11'
ZeroExtend(‘1’:imm12<6:0>, 32) means you have to prepend '1' to [6..0] bits. So the value becomes 1:1110000 = 11110000
(a)
ROR_C(unrotated_value, UInt(imm12<11:7>)) does rotate right by [11:7] = 11111 = 31 which is the same as rotate left by 1
. (b)
So the resulting value is 1 1110 0000 (a shifted by b) = 0x1e0
Upvotes: 2
Reputation: 71516
For arm the instructions are described in the ARM ARM, ARM Architectural Reference manual(s). Go to http://infocenter.arm.com then along the left find architecture then find the architecture you are interested in. This is a thumb2 instruction so you want the armv7-m.
This looks to be encoding T2
11110i00010S11110...
i and S are zero in your instruction. imm3 is bits 12 to 14 and imm8 is bits 7 - 0.
0 111 0001 11110000
so your imm3 is 0b111 and imm8 is 0b11110000
then you look at the modified immediate constants in thumb instructions section
i ... imm3 ... abcdefgh where abcdefgh are the imm8 bits your i:imm3:a bits, 5 bits are 0b11111
so you look that up in the table and you get imm8 on the right side shifted left 1
00000000 00000000 00000001 bcdefgh0
00000000 00000000 00000001 11100000
which is 0x000001E0
Arm does a pretty good job of documenting their instructions, better than most.
Upvotes: 2