Как я могу попросить ассемблера "дать мне полный размер реестра"?

Я пытаюсь разрешить ассемблеру дать мне регистр, который он выбирает, а затем использовать этот регистр с встроенной сборкой. Я работаю с приведенной ниже программой и ее разрывом. Программа была скомпилирована с помощью g++ -O1 -g2 -m64 wipe.cpp -o wipe.exe.

Когда я смотрю на crash под lldb, я считаю, что получаю 32-битный регистр, а не 64-битный регистр. Я пытаюсь вычислить адрес (base + offset) с помощью lea и сохранить результат в регистре, который выбирает ассемблер:

"lea (%0, %1), %2\n"

Выше, я пытаюсь сказать "использовать регистр, и я буду ссылаться на него как% 2".

Когда я выполняю разборку, я вижу:

   0x100000b29:  leal   (%rbx,%rsi), %edi
-> 0x100000b2c:  movb   $0x0, (%edi)

Итак, кажется, что сгенерированный код вычисляет и адресует с использованием 64-битных значений (rbx и rsi), но сохраняет его в 32-битный регистр (edi) (который выбрал ассемблер).

Ниже приведены значения во время сбоя:

(lldb) type format add --format hex register
(lldb) p $edi
(unsigned int) $3 = 1063330
(lldb) p $rbx
(unsigned long) $4 = 4296030616
(lldb) p $rsi
(unsigned long) $5 = 10

Быстрая заметка о операндах ввода ниже. Если я опустил "r" (2), тогда я получаю ошибку компилятора, когда я обращаюсь к %2 в вызове lea: invalid operand number in inline asm string.

Как сообщить ассемблеру "дать мне полный регистр размера", а затем обратиться к нему в моей программе?


int main(int argc, char* argv[])
{
    string s("Hello world");
    cout << s << endl;

    char* ptr = &s[0];
    size_t size = s.length();

    if(ptr && size)
    {
        __asm__ __volatile__
        (
         "%=:\n"                /* generate a unique label for TOP */

         "subq $1, %1\n"        /* 0-based index */
         "lea (%0, %1), %2\n"   /* calcualte ptr[idx] */
         "movb $0, (%2)\n"      /* 0 -> ptr[size - 1] .. ptr[0] */
         "jnz %=b\n"            /* Back to TOP if non-zero */

         : /* no output */
         :  "r" (ptr), "r" (size), "r" (2)
         : "0", "1", "2", "cc"
         );
    }

    return 0;
}

Извините за эти встроенные вопросы сборки. Надеюсь, это последнее. Я не очень взволнован тем, что использовал встроенную сборку в GCC из-за таких болевых точек (и моей угасающей памяти). Но его единственный юридический способ, которым я знаю, делать то, что я хочу сделать, с учетом интерпретации GCC классификатора volatile в C.

Если это интересно, GCC интерпретирует классификатор C volatile как аппаратная резервная память, а все остальное - злоупотребление, и это приводит к незаконной программе, Ниже приведено не право для GCC:

volatile void* g_tame_the_optimizer = NULL;
...

unsigned char* ptr = ...
size_t size = ...;

for(size_t i = 0; i < size; i++)
   ptr[i] = 0x00;

g_tame_the_optimizer = ptr;

Интересно, что Microsoft использует более обычную интерпретацию volatile (что большинство программистов ожидают, а именно, что-то может изменить память, а не только аппаратное обеспечение с отображением памяти), и приведенный выше код является приемлемым.

Ответ 1

gcc inline asm - сложный зверь. "r" (2) означает выделить регистр размера int и загрузить его со значением 2. Если вам просто нужен произвольный регистратор царапин, вы можете объявить 64-битный фиктивный вывод в виде кубика, например "=&r" (dummy) в разделе вывода, с объявленным ранее void *dummy. Подробнее см. gcc manual.

Что касается окончательного фрагмента кода, похоже, что вам нужен барьер памяти, как указано в связанном письме. См. Руководство .