Как я могу попросить ассемблера "дать мне полный размер реестра"?
Я пытаюсь разрешить ассемблеру дать мне регистр, который он выбирает, а затем использовать этот регистр с встроенной сборкой. Я работаю с приведенной ниже программой и ее разрывом. Программа была скомпилирована с помощью 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.
Что касается окончательного фрагмента кода, похоже, что вам нужен барьер памяти, как указано в связанном письме. См. Руководство .