рука встроенная сборка в GCC - PullRequest
4 голосов
/ 16 февраля 2012

У меня возникли проблемы с некоторым встроенным кодом сборки. Я знаю, что нужно сделать, но я скучаю по «как»!

У меня есть эта функция контрольной суммы, которая "почти" работает:

static unsigned long cksum_unroll( unsigned short **w, int *mlen)
{
  int len;
  unsigned short *w0;
  unsigned long sum=0;

  len = *mlen;
  w0 = *w;

  while( len >= 8) {
    asm volatile (
          "ldmia %[w0]!, {v1, v2}\n\t"
          "adds %[sum], %[sum], v1\n\t"
          "adcs %[sum], %[sum], v2\n\t"
          "adcs %[sum], %[sum], #0"
          : [sum] "+r" (sum) : [w0] "r" (w0)
          );
    len -= 8;
  }
  *mlen = len;
  *w = w0;
  return (sum);
}

Моя проблема, я полагаю, заключается в строке ": [sum]" + r "(sum): [w0]" r "(w0) " На первой сборочной линии w0 корректно обрабатывается с помощью ldmia (когда строка выполняется, данные находятся в r4, r5 и w0 увеличивается). Но увеличенное значение w0 где-то не сохраняется, и когда в цикле кода снова загружается исходное значение w0 (см. Код сборки ниже). Я предполагаю, что я должен хранить значение w0 в строке ": [sum]" + r "(sum): [w0]" r "(w0)", но я не знаю, как ...

Вот код разборки встроенной части сборки функции:

Обратите внимание, что:

len is stored at r11, #-16
w0 is stored at r11, #-20
sum is stored at r11, #-24

Скомпилирован следующий код:

asm volatile (
          "ldmia %[w0]!, {v1, v2}\n\t"
          "adds %[sum], %[sum], v1\n\t"
          "adcs %[sum], %[sum], v2\n\t"
          "adcs %[sum], %[sum], #0"
          : [sum] "+r" (sum) : [w0] "r" (w0)
);
len -= 8;

Генерировать:

00031910:   ldr r3, [r11, #-20]
00031914:   ldr r2, [r11, #-24]
00031918:   mov r4, r2
0003191c:   ldm r3!, {r4, r5}
00031920:   adds r4, r4, r4
00031924:   adcs r4, r4, r5
00031928:   adcs r4, r4, #0
0003192c:   str r4, [r11, #-24]
00031930:   ldr r3, [r11, #-16]
00031934:   sub r3, r3, #8
00031938:   str r3, [r11, #-16]

Как видите, я хотел бы добавить что-то вроде "str r3, [r11, # -20]" между строками 31928 и 3192c, потому что когда цикл программы к строке 31910, r3 загружается с начальным значением r3 ...

Я думаю, что это легко для эксперта по встроенной сборке сообщества переполнения стека!

Кстати, я работаю на процессоре ARM7TDMI (но это может не относиться к этому вопросу ...)

Заранее спасибо!

EDIT:

Чтобы проверить мою идею, я проверил следующее:

asm volatile ( 
"ldmia %[w0]!, {v1, v2}\n\t" 
"adds %[sum], %[sum], v1\n\t" 
"adcs %[sum], %[sum], v2\n\t" 
"adcs %[sum], %[sum], #0\n\t" 
"str %[w0], [r11, #-20]" 
: [sum] "+r" (sum) : [w0] "r" (w0) 
); 

И это работает. Может быть, это решение, но что мне использовать для замены «r11, # 20», которое, вероятно, изменится, если я изменю функцию?

1 Ответ

4 голосов
/ 16 февраля 2012

Может показаться, что проблема заключается в том, что вы задаете w0 в качестве операнда INPUT, когда он на самом деле должен быть операндом OUTPUT для чтения и записи, например sum.Кроме того, вам нужно указать, что он перекрывает v1 и v2 при использовании этих регистров (в противном случае gcc может поместить в эти регистры некоторые другие переменные и ожидать их сохранения.)

Таким образом, вы должны иметь:

asm volatile (
      "ldmia %[w0]!, {v1, v2}\n\t"
      "adds %[sum], %[sum], v1\n\t"
      "adcs %[sum], %[sum], v2\n\t"
      "adcs %[sum], %[sum], #0"
      : [sum] "+r" (sum) , [w0] "+r" (w0) : : "v1", "v2"
      );

, то есть два операнда ввода-вывода с чтением и записью, нет только операндов ввода и два констебля регистра

...