I'm a little stuck trying to understand this simple piece of code. It get's a number in R0. The first part seems to be a R0 = abs(R0), but then it get's more difficult. The number of leading zeros is determined, then it's left shifted by that many bits and then it's checked if that is > 0, otherwise 0 is returned. I don't get what the purpose of the entire shifting there is supposed to be and what the Add and additional shift operations are supposed to do there.

ROM:0005B7BE ; =============== S U B R O U T I N E =======================================
ROM:0005B7BE sub_5B7BE
ROM:0005B7BE                 ANDS.W  R2, R0, #0x80000000
ROM:0005B7C2                 IT MI
ROM:0005B7C4                 NEGMI   R0, R0
ROM:0005B7C6                 CLZ.W   R3, R0
ROM:0005B7CA                 LSLS.W  R1, R0, R3
ROM:0005B7CE                 BEQ     retZero
ROM:0005B7D0                 RSB.W   R3, R3, #29
ROM:0005B7D4                 ADD.W   R3, R3, #1024
ROM:0005B7D8                 MOV.W   R0, R1,LSL#21
ROM:0005B7DC                 ADD.W   R2, R2, R3,LSL#20
ROM:0005B7E0                 ADD.W   R1, R2, R1,LSR#11
ROM:0005B7E4                 BX      LR
ROM:0005B7E6 ; ---------------------------------------------------------------------------
ROM:0005B7E6 retZero
ROM:0005B7E6                 MOV.W   R0, #0
ROM:0005B7EA                 BX      LR
ROM:0005B7EA ; End of function sub_5B7BE
  • Have you tried using hex-rays/ghidra decompiler to see the auto decompile results? – macro_controller Jun 9 at 9:47
  • 3
    If it's so "simple", why do you need help? ;) – Igor Skochinsky Jun 9 at 14:06

This is function dflt (or __aeabi_i2d) from the ARM compiler libraries. It performs a conversion of a 32-bit signed integer in R0 into a a soft-float double (64-bit floating point value) in R0:R1.

An IEEE 754 double consists of a sign bit, 11-bit exponent and 52-bit fraction:

 63  62             52 51                                         0
| s | exponent(11)    |           fraction(52)                     |
|           R1                |             R0                     |
31                           0 31                                 0  

The value of the number is 2^(e-1023)*1.fraction

The code calculates the exponent and fraction that would approximate the original value and puts it into R0:R1. The magic numbers in shifts are necessary to line up the fraction across the two registers and 1024 is the bias for the exponent.

| improve this answer | |
  • Thank you very much, I really appreciate it :) The reason I needed help was that the decompiler probably confused me a little: It didn't pick up R1 at all, so it basically only did a if(a1 << clz(a1)) return a1 << clz(a1) << 21 else return 0 which is obviously completely wrong. When I looked at the assembly I only focused on R0 and didn't think about a value larger than R0. Lack of experience I guess ;) – Roman Jun 9 at 17:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.