Какое ограничение неверно с этой встроенной сборкой? - PullRequest
0 голосов
/ 07 мая 2020

У меня есть встроенная сборка x86 (32-разрядная) в коде C ++, который компилируется для 32-разрядной Linux с помощью g cc 9.3.0. В конце вызова asm я получаю ошибку 'asm' has impossible constraints. Он не сообщает мне , какие ограничения являются «невозможными» и почему.

Я понимаю синтаксис оператора __asm__(...), как описано здесь , и я потратил некоторое время, пытаясь доказать, почему каждое ограничение является правильным, но я не могу понять, какие ограничения использовать добавить или удалить сборку, нарушающую ограничение.

Вот код:

extern int    view_pitch;
static int    scale;
static int    rle_remainder;
static int    height;
static short *color_table;
static PIXEL *RLE_palette;
static int    repeat;
static PIXEL *dest;
static UCHAR *src;

void RLE_blit(void)
{
  __asm__ __volatile__ (
  "     mov %2, %%edi\n"
  "     push %%ebp\n"
  "     mov %3, %%edx\n"
  "mloop:\n"

  "     xor %%ecx, %%ecx\n"
  "     mov (%%edx), %%cl\n"
  "     add $0x2, %%edx\n"
  "     imul %4, %%ecx\n"
  "     add %0, %%ecx\n"
  "     xor %%eax, %%eax\n"
  "     mov %%ecx, %%ebx\n"
  "     and $0xffff, %%ecx\n"
  "     shr $0x10, %%ebx\n"
  "     mov %%ecx, %0\n"
  "     cmp $0x0, %%ebx\n"
  "     jbe mloop\n"

  // color region code
  "     mov -0x1(%%edx), %%al\n"

  "     mov %%eax, %%ecx\n"           // save orginal pixel in eax
  "     and $0x1f, %%eax\n"           // now modulo original pixel by 32 to get offset
  "     mov %5, %%esi\n"              // pointer to color table
  "     jz bypass\n"

  "     shr $0x5, %%ecx\n"            // divide pixel by 32 to get region
  "     mov (%%esi,%%ecx,2), %%cx\n"  // get region number from region array into cx
  "     shl $0x5, %%ecx\n"            // multiply by 32 to get start of region

  "     mov %6, %%esi\n"
  "     add %%ecx, %%eax\n"           // add offset
  "     mov (%%esi,%%eax,2), %%ax\n"

  "     cmp %1, %%ebx\n"              // is run length <= than remaining column height
  "     jbe no_run_len_adjust\n"      // yes: don't adjust
  "     mov %1, %%ebx\n"              // no : set run length to height

  "no_run_len_adjust:\n"

  "     sub %%ebx, %1\n"

  "     mov %7, %%ebp\n"
  "     mov %8, %%esi\n"

  "run_len_loop:\n"                   // BEGIN outer run length loop
  "     mov %%ebp, %%ecx\n"

  "col_loop:\n"                       // BEGIN inner column repeat loop
  "     dec %%ecx\n"
  "     mov %%ax, (%%edi,%%ecx,2)\n"
  "     jnz col_loop\n"               // END column repeat loop

  "     add %%esi, %%edi\n"
  "     dec %%ebx\n"
  "     jnz run_len_loop\n"           // END run length loop

  "     cmp $0x0, %1\n"
  "     jg mloop\n"
  "     jmp exit1\n"

  "bypass:\n"
  "     mov %%ebx, %%eax\n"
  "     imul %8, %%eax\n"
  "     add %%eax, %%edi\n"

  "     sub %%ebx, %1\n"
  "     cmp $0x0, %1\n"
  "     jg mloop\n"

  "exit1:\n"
  "     pop %%ebp\n"
  :"+m"(rle_remainder), "+m"(height)
  :"m"(dest), "m"(src), "m"(scale), "m"(color_table), "m"(RLE_palette), "m"(repeat), "m"(view_pitch)
  :"esi", "edi", "eax", "ebx", "ecx", "edx", "memory"
  );
}

Вот краткое изложение того, почему я думаю то, что у меня есть справа:

  • Выходы: rle_remainder и height читаются и записываются, поэтому +m подходит.
  • Входные данные: dest, src, scale, color_table, RLE_palette, repeat и view_pitch отображаются только для чтения; они не находятся в позиции «назначения» ни в одной инструкции. Таким образом, m означает, что они (только) считываются из.
  • Список закрытых регистров ("esi", "edi", "eax", "ebx", "ecx", "edx") содержит все регистры, которые были изменены. Поскольку некоторые из модифицированных регистров являются 8- или 16-разрядными «частями» этих регистров, например ax, эти части регистров не нужно явно указывать, потому что весь 32-разрядный регистр является частью of уже указан как clobbered.
  • "memory" указан как clobbered, чтобы обеспечить барьер чтения / записи для адресов памяти, в которые выполняется запись, а не только для ячеек памяти самих выходов. Например, mov %%ax, (%%edi,%%ecx,2) уничтожает память.
  • Я не использовал ключевое слово goto, потому что не используются метки C - единственные метки, на которые выполняется переход - это метки внутри этого блока встроенной сборки.
  • Указатель кадра ebp изменяется в ходе выполнения кода, но восстанавливается в конце, поэтому я не указал его как затертый. Если я его перечислю, g cc выдаст ошибку, потому что вам не разрешено сообщать g cc, что вы больше не смываете указатель кадра, я не думаю. В любом случае, код не может быть скомпилирован с или без ebp, названного как затертый.
  • Предположение: может ли он жаловаться, что ebp вообще изменяется ? Даже если мы восстановим его значение обратно к исходному в конце кода - гарантированно - если программа не выйдет из строя? В документации не было ясно, является ли правило «вы не можете изменить ebp вообще , даже временно» или «если вы изменяете ebp, значение в конце вашего встроенного asm должен быть восстановлен до оригинала ". Если это первое, то мой код неверен, потому что ebp изменяется во время выполнения этого кода.

Ясно, что мне что-то не хватает в ожиданиях g cc в отношении ограничений или сборка, но я не могу определить, что это.

...