2015-03-28 2 views
1

Я пытаюсь преобразовать существующую встроенную сборку x86_64 в совместимую с AArch64 версию. Я встречая следующие ошибки при компиляции:Портирование x86_64 Сборка в AArch64

/tmp/ccSvqF1I.s:72547: Error: operand 1 should be an integer register -- `str [0x4,x1],#0x43e00000' 
/tmp/ccSvqF1I.s:72548: Error: operand 1 should be an integer register -- `str [20,x1],2' 

x86_64 код ниже, если исходный и код AARch64 моя попытка переносить его.

x86_64 Монтаж:

   __asm__(
         "incq (%0)\n\t" 
         "jno 0f\n\t" 
         "movl $0x0, (%0)\n\t" 
         "movl $0x43e00000, 0x4(%0)\n\t" 
         "movb %1, %c2(%0)\n" 
         "0:" 
         : 
         : "r"(&op1->value), 
          "n"(IS_DOUBLE), 
          "n"(ZVAL_OFFSETOF_TYPE) 
         : "cc"); 

AArch64 Ассамблея

   __asm__(
         "add %0, %0, #1\n\t" 
         "bvc 0f\n\t" 
         "mov %0, #0x0\n\t" 
         "str [0x4, %0], #0x43e00000\n\t" 
         "str [%c2, %0], %1\n\t" 
         "0:" 
         : 
         : "r"(&op1->value), 
          "n"(IS_DOUBLE), 
          "n"(ZVAL_OFFSETOF_TYPE) 
         : "cc"); 

Edit: обновление с новой попыткой и сообщения об ошибках

+3

Не смысл звучать грубо, но вам, вероятно, следует попробовать использовать инструкции и синтаксис AArch64, в отличие от того, что это такое. – Notlikethat

+0

@Notlikethat Я предполагаю, что моя реальная проблема не понимает часть '% c2 (% 0)' кода x86. Кажется, я не могу найти документацию, описывающую, что делает этот код. – Grice

+1

Моя сборка x86 довольно ржавая, и я знаю, что это мой синтаксис Intel, а не глупый синтаксис AT & T GNU, но я думаю, что это просто базовый регистр + немедленная адресация смещения с ограничением, что 'ZVAL_OFFSETOF_TYPE' должно быть константой времени компиляции - см. [«Охотники-модификаторы x86» в документах] (https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Extended-Asm). В любом случае любой операнд памяти не подходит для команды ARM 'mov'. – Notlikethat

ответ

0

Если вы хотите сделать что-то не может быть описания по одной инструкции вам нужно разбить ее на несколько инструкций.

Проблема заключается в том, что у AArch64 нет инструкции хранить немедленное значение в памяти. Вы должны переместить непосредственное значение в регистр, а затем сохранить регистр память, как:

movz w2, #0x43e0, lsl #16   // move #0x43e00000 to a register 
str w2, [x1, #20]     // store to address [x1, #20] 
orr w2, wzr, #0x2     // move #0x2 to a register 
str w2, [x1, #4]      // store to address [x1, #4] 

инструкция ARM является RISC (компьютер с сокращенным набором команд), как инструкция. Преимущество состоит в том, что все инструкции очень просты и фиксированы. X86 содержит более сложные инструкции. Но вам все равно нужно разделить свое поведение на несколько инструкций, если у него нет инструкции, поддерживающей ваше поведение. Вы можете найти более подробную информацию о AArch64 в http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0488d/CIHGGBGB.html.

0

Лучшим решением может быть использование ldr= псевдо-оп, который позволит сделать зашифрованное movz использование легче читать:

ldr w2, =0x43e00000 
str w2, [x1, #20] 

.. и так далее. Ваш ассемблер должен быть достаточно умным, чтобы понять, что он может использовать movz или какую-либо другую команду для генерации немедленного значения в w2, но в худшем случае это будет выглядеть как литерный пул. Во время обучения ldr= является благом, и вы не должны пытаться играть в ассемблер, пока не узнаете, что он сломан или не так эффективен, как вы.

+0

Нам нужен переводчик, чтобы понять этот ответ. –

0

К сожалению, почти ни одна из ваших сборок не является правильной. Набор инструкций A64 использует архитектуру загрузки/хранения. Это означает, что есть определенная инструкция, которая загружает и сохраняет значения из памяти в регистры и из них. Никаких других инструкций не требуется для доступа к памяти. Так, например, инструкция ADD не может получить доступ к памяти. Это означает, что ваш оператор add %0, %0, #1 не увеличивает op1->value, он увеличивает регистр, который содержит адрес op1->value. Это похоже на то, что вы сделали op1++ в C вместо op1->value++.

zend_long temp; 
    static zend_long const overflow = 0x43e0000000000000; 
    asm("ldr %[temp], %[value]\n\t" 
     "adds %[temp], %[temp], #1\n\t" 
     "str %[temp], %[value]\n\t" 
     "b.vc 0f\n\t" 
     "mov %[temp], #%[overflow]\n\t" 
     "str %[temp], %[value]\n\t" 
     "mov %w[temp], #%[is_double]\n\t" 
     "str %w[temp], %[type_info]\n\t" 
     "0:\n\t" 
     : 
     [temp] "=&r" (temp), 
     [value] "+m" (op1->value.lval), 
     [type_info] "=m" (op1->u1.type_info) 
     : 
     [overflow] "N" (overflow), 
     [is_double] "M" (IS_DOUBLE) 
     : "cc"); 

Вы заметите, что инструкция x86 INC становится тремя отдельными инструкциями. Первые загружают значение в регистр, второе добавляет его в регистр и, наконец, третий сохраняет его обратно.

Две константы 0x43e000000000000 и IS_DOUBLE являются теми, которые могут быть загружены в регистр с помощью одной команды. Использование псевдо-команды MOV позволяет ассемблеру выяснить, какой из них.В противном случае вместо команды LDR = pseudo потребуется загрузить константу из памяти. В любом случае, как сказал глэймор в своем ответе, вы не можете хранить непосредственное значение непосредственно в памяти.

Наконец, оператор asm использует инструкцию ADDS вместо инструкции ADD. Первый устанавливает флаги условий в соответствии с результатом, а позже - нет. Вся эта точка утверждения asm. Он должен сделать более эффективным обнаружение переполнения, проверив флаги условий.

Смежные вопросы