Как закодировать непосредственное значение в руке?

Предположим, что есть такой инст:

add  ip, ip, #0x5000

машинный код

05 CA 8C E2

а также

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

Но если мы знаем 0x5000, как мы можем получить 101000000101? Это обратное преобразование взаимно однозначной корреспонденции? Спасибо.


person scvyao    schedule 20.07.2013    source источник
comment
Связано, для AArch64: диапазон непосредственных значений в сборке ARMv8 A64   -  person Peter Cordes    schedule 25.02.2021


Ответы (1)


От ARM ARM:

ADD добавляет два значения. Первое значение поступает из регистра. Второе значение может быть либо немедленным значением, либо значением из регистра, и может быть сдвинуто перед добавлением.

Непосредственное значение, которое вы видите, смещается. Биты 11:0 вашей инструкции являются операндом сдвига - в вашем случае: 0xA05.

Позже в документах описан этот режим адресации:

Значение <shifter_operand> формируется путем поворота (вправо) 8-битного непосредственного значения в любую четную битовую позицию в 32-битном слове.

Таким образом, ваш конкретный операнд сдвига означает, что 0x05 повернут вправо на (2 * 10) бит.

У вас есть несколько вариантов, если вы выполняете кодирование инструкций. Например:

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

Я вручную закодировал их для дизассемблирования:

$ 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

Вот простая программа, которая может найти кодировки:

#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;
}

И пример для вашего случая:

$ ./example 0x5000
0xA05
0xB14
0xC50
person Carl Norum    schedule 20.07.2013
comment
Отредактировано, чтобы добавить несколько примеров. - person Carl Norum; 20.07.2013
comment
Не могли бы вы написать свою конвертацию арифметики на C? преобразовать (0x5000) = 0xA05, 0xB14, ... - person scvyao; 20.07.2013
comment
Хорошо, я добавил программу для генерации кодировок. - person Carl Norum; 20.07.2013
comment
К сожалению, этот код C не работает, когда адрес 32-битный (например, 0xdeadbeef) - person Sama Azari; 21.06.2016
comment
@SamaAzari - как же так? Это значение не может быть помещено в 8-битное непосредственное значение. 0xde000000 — это 32-битный адрес, и он должен работать нормально. - person Carl Norum; 21.06.2016