Как замаскировать байты в сборке ARM? - PullRequest
7 голосов
/ 07 декабря 2008

У меня есть 32-битное (шестнадцатеричное) слово 0xaabbccdd, и я должен поменять местами 2. и 3. байт. в конце это должно выглядеть как 0xaaccbbdd

как я могу "замаскировать" 2-й и 3-й байты, чтобы сначала загрузить их, чтобы зарегистрировать r1 и r2 и поменять их местами я также знаю, что мне нужно работать с командами lsl и lsr, но я не знаю с чего начать.

Извините за мой плохой английский. Надеюсь, кто-нибудь может мне помочь!

С уважением, Себастиан

Ответы [ 5 ]

8 голосов
/ 09 июля 2009

В те времена, когда мы привыкли полагаться на EOR для такого рода хитрости.

Вы можете сделать это за 4 цикла.

Прежде всего, нам нужен тот факт, что: A ^ (A ^ B) = B

Мы начинаем с 0xAABBCCDD, и мы хотим 0xAACCBBDD. Чтобы попасть туда, нам нужно 0x00EEEE00 ^ 0xAABBCCDD, где EE = BB ^ CC.

Теперь нам нужно несколько циклов для сборки 00EEEE00:

eor     r1,r0,r0,lsr #8
and     r1,r1,#0xFF00
orr     r1,r1,r1,lsl #8
eor     r0,r0,r1

В к:

t=x^(x>>8);
t=t&0xFF00;
t=t|(t<<8);
x^=t;

После каждой строки рассчитывается следующий результат: начиная с: AABBCCDD

eor  XXXXEEXX
and  0000EE00
orr  00EEEE00
eor  AACCBBDD

Это будет работать на любом 32-битном ядре ARM.

6 голосов
/ 07 декабря 2008

Это не простая задача в сборке ARM, потому что вы не можете легко использовать 32-битные константы. Вы должны разбить все ваши операции, которые маскируют байты, чтобы использовать 8-битные константы каждая (также эти константы можно вращать).

Вы маскируете байты 2 и 3 с помощью инструкции AND и делаете сдвиг позже. в ARM-ассемблере у вас есть большинство инструкций на одну смену бесплатно, поэтому переход в положение и слияние с другими битами часто заканчиваются одной инструкцией.

Вот некоторый непроверенный код, который выполняет перестановку средних байтов (ARMv4, а не набор команд большого пальца):

        .text

swap_v4:
        AND     R2, R0, #0x00ff0000     @ R2=0x00BB0000 get byte 2
        AND     R3, R0, #0x0000ff00     @ R3=0x0000CC00 get byte 1
        BIC     R0, R0, #0x00ff0000     @ R0=0xAA00CCDD clear byte 2
        BIC     R0, R0, #0x0000ff00     @ R0=0xAA0000DD clear byte 1
        ORR     R0, R2, LSR #8          @ R0=0xAA00BBDD merge and shift byte 2
        ORR     R0, R3, LSL #8          @ R0=0xAACCBBDD merge and shift byte 1
        B       LR

Это переводит построчно в следующий c-код:

int swap (int R0)
{
  int R2,R3;
  R2 = R0 & 0x00ff0000;
  R3 = R0 & 0x0000ff00;
  R0 = R0 & 0xff00ffff;
  R0 = R0 & 0xffff00ff;
  R0 |= (R2>>8);
  R0 |= (R3<<8);
  return R0;
}

Вот увидите - много строк для такой простой задачи. Даже архитектура ARMv6 здесь не очень помогает.


РЕДАКТИРОВАТЬ: версия ARMv6 (также не проверено, но две инструкции короче)

swap_v6:
        @ bits in R0: aabbccdd
        ROR     R0, R0, #8              @ r0 = ddaabbcc
        REV     R1, R0                  @ r1 = ccbbaadd
        PKHTB   R0, R0, R1              @ r0 = ddaaccbb
        ROR     R0, R0, #24             @ r0 = aaccbbdd
        BX      LR
2 голосов
/ 29 апреля 2009

Хммм, не знаю, что случилось, он отправил мой ответ, прежде чем я действительно начал.

Сначала я не думал, что смогу сделать это только с двумя регистрами, но потом решил, что смогу и сделал. Эти решения только для регистров, без памяти (кроме ldr r0, = который можно заменить четырьмя инструкциями). Если вы используете память и хммм, два регистра, вы можете сократить количество инструкций, возможно, str, bic, bic, ldrb, orr lsl, ldrb, orr lsl. Хорошо, я сделал это за одну инструкцию меньше, но тогда вам понадобится место в памяти, а также циклы затрат на хранение и загрузку, так же количество памяти и больше циклов для меня, чтобы сделать это с памятью. У кого-то еще могут быть хорошие трюки. Я думаю, что у некоторых из новых ядер есть инструкция подстановки с порядком байтов, которая сделает это еще проще.

.globl midswap
midswap:
    mov r2,r0,lsl #8      ;@ r2 = BBCCDDAA
    mov r3,r0,lsr #8      ;@ r3 = DDAABBCC (this might drag a sign bit, dont care)
    and r2,r2,#0x00FF0000 ;@ r2 = 00CC0000
    and r3,r3,#0x0000FF00 ;@ r3 = 0000BB00
    bic r0,r0,#0x00FF0000 ;@ r0 = AA00CCDD
    bic r0,r0,#0x0000FF00 ;@ r0 = AA0000DD
    orr r0,r0,r2          ;@ r0 = AACC00DD
    orr r0,r0,r3          ;@ r0 = AACCBBDD
    bx lr ;@ or mov pc,lr for older arm cores


.globl tworegs
tworegs:
    mov r2,r0,ror #8       ;@ r2 = DDAABBCC
    bic r2,r2,#0xFF000000  ;@ r2 = 00AABBCC
    bic r2,r2,#0x00FF0000  ;@ r2 = 0000BBCC
    orr r2,r2,ror #16      ;@ r2 = BBCCBBCC
    bic r2,r2,#0xFF000000  ;@ r2 = 00CCBBCC
    bic r2,r2,#0x000000FF  ;@ r2 = 00CCBB00
    bic r0,r0,#0x00FF0000  ;@ r0 = AA00CCDD
    bic r0,r0,#0x0000FF00  ;@ r0 = AA0000DD
    orr r0,r0,r2           ;@ r0 = AACCBBDD
    bx lr

testfun:
    ldr r0,=0xAABBCCDD
    bl midswap
1 голос
/ 30 апреля 2014

Можете ли вы использовать BFI и UBFX, они облегчат вашу работу

0 голосов
/ 08 декабря 2008

Вы должны просто использовать указатели для замены двух байтов

static union {
 BYTE   BBuf[4];
 WORD   WWBuf[2];
 DWORD  DWBuf;
}swap;

unsigned char *a;
unsigned char *b;
swap.DWBuf = 0xaabbccdd;

a = &swap.BBuf[1];
b = &swap.BBuf[2];

*a ^= *b;
*b ^= *a;
*a ^= *b;

А теперь результат

swap.DWbuf == 0xaaccbbdd;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...