4

Suppose there is an inst like this:

add  ip, ip, #0x5000

the machine code is

05 CA 8C E2

and

E2 8C CA 05 = 11100010100011001100 1010 00000101
imm = rotate_right(101B, 1010B*2) = 0x5000

But if we know 0x5000, how can we get 101000000101? Is this reverse convert one-to-one correspondence? Thanks.

1

1 Answer 1

11

From the ARM ARM:

ADD adds two values. The first value comes from a register. The second value can be either an immediate value or a value from a register, and can be shifted before the addition.

The immediate value you're seeing is being shifted. Bits 11:0 of your instruction are the shifter operand - in your case: 0xA05.

Later in the docs, that addressing mode is described:

The <shifter_operand> value is formed by rotating (to the right) an 8-bit immediate value to any even bit position in a 32-bit word.

So your specific shifter operand means 0x05 rotated right by (2 * 10) bits.

You have a few choices if you're doing the instruction encoding. For example:

0xA05 // rotate 0x05 right by 20
0xB14 // rotate 0x14 right by 22
0xC50 // rotate 0x50 right by 24

I hand encoded them to disassemble:

$ xxd -r > example
00 05 CA 8C E2 14 CB 8C E2 50 CC 8C E2
$ arm-none-eabi-objdump -m arm -b binary -D example

example:     file format binary


Disassembly of section .data:

00000000 <.data>:
   0:   e28cca05    add ip, ip, #20480  ; 0x5000
   4:   e28ccb14    add ip, ip, #20480  ; 0x5000
   8:   e28ccc50    add ip, ip, #20480  ; 0x5000

Here's a simple program that can find the encodings:

#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>

int main(int argc, char **argv)
{
    uint32_t encode = strtoul(argv[1], NULL, 0);
    int rotate;

    for (rotate = 0; rotate < 32; rotate += 2)
    {
        // print an encoding if the only significant bits 
        // fit into an 8-bit immediate
        if (!(encode & ~0xffU))
        {
            printf("0x%X%02X\n", rotate/2, encode);
        }

        // rotate left by two
        encode = (encode << 2) | (encode >> 30);
    }
    return 0;
}

And an example run for your case:

$ ./example 0x5000
0xA05
0xB14
0xC50
5
  • Edited to add some examples.
    – Carl Norum
    Commented Jul 20, 2013 at 15:20
  • Would you mind write your convert arithmetic in C? convert(0x5000) = 0xA05, 0xB14, ...
    – scvyao
    Commented Jul 20, 2013 at 15:31
  • OK, I added a program to generate the encodings.
    – Carl Norum
    Commented Jul 20, 2013 at 15:47
  • Unfortunately that C code does not work when the address is 32 bit (e.g. 0xdeadbeef)
    – Sama Azari
    Commented Jun 21, 2016 at 15:40
  • 1
    @SamaAzari - how could it? That value can't be made to fit in an 8-bit immediate. 0xde000000 is a 32-bit address and should work fine, though.
    – Carl Norum
    Commented Jun 21, 2016 at 20:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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