Использование функциональных меток в встроенной сборке

Я играю со встроенной сборкой в ​​C ++, используя gcc-4.7 на 64-битной Ubuntu 12.04 LTS с прямым порядком байтов с Eclipse CDT и gdb. Общее направление того, что я пытаюсь сделать, — это создать своего рода интерпретатор байт-кода для некоторого эзотерического стекового языка программирования.

В этом примере я обрабатываю инструкции по 4 бита за раз (на практике это будет зависеть от инструкции), и когда больше нет ненулевых команд (так как 0 будет nop), я читаю следующие 64-битные слова ,

Я хотел бы спросить, хотя, Как использовать функциональную метку при встроенной сборке?

Кажется, что метки в ассемблере являются глобальными, что неблагоприятно, и я не могу найти способ перейти к метке области действия C ++ из инструкции ассемблера.

Следующий код является примером того, что я пытаюсь сделать (обратите внимание на комментарий):

  ...
register long ip  asm("r8");
register long buf asm("r9");
register long op  asm("r10");
...
fetch:
asm("mov (%r8), %r9");
asm("add $8, %r8");
control:
asm("test %r9, %r9");
asm("jz   fetch"); // undefined reference to `fetch'
asm("shr  $4, %r9");
asm("mov  %r9, %r10");
asm("and  $0xf, %r10");
switch (op) {
...
}
goto control;

0

Решение

Обратите внимание на следующий комментарий в документации gcc inline asm:

Говоря о метках, переходы с одного `asm ‘на другой не поддерживаются.
Оптимизаторы компилятора не знают об этих переходах, и поэтому
они не могут учитывать их при принятии решения о том, как оптимизировать.

Вы также не можете полагаться на флаги, установленные в одном asm будет доступен в следующем, так как компилятор может вставить что-то между ними

С gcc 4.5 и выше вы можете использовать asm goto делать то, что вы хотите:

fetch:
asm("mov (%r8), %r9");
asm("add $8, %r8");
control:
asm goto("test %r9, %r9\n\t""jz  %l[fetch]" : : : : fetch);

Обратите внимание, что все остальное в вашем asm совершенно небезопасно, так как использует регистры напрямую, не объявляя их в своих списках чтения / записи / засечек, поэтому компилятор может решить добавить в них что-то еще (несмотря на переменные с asm декларации о них — он может решить, что они мертвы, поскольку они никогда не используются). Поэтому, если вы ожидаете, что это на самом деле будет работать с -O1 или выше, вам нужно записать это как:

  ...
long ip;
long buf;
long op;
...
fetch:
asm("mov (%1), %0" : "=r"(buf) : "r"(ip));
asm("add $8, %0" : "=r"(ip) : "0"(ip));
control:
asm goto("test %0, %0\n\t""jz   %l[fetch]" : : "r"(buf) : : fetch);
asm("shr  $4, %0" : "=r"(buf) : "0"(buf));
asm("mov  %1, %0" : "=r"(op) : "r"(buf));
asm("and  $0xf, %0" : "=r"(op) : "r"(op));

В этот момент гораздо проще просто написать его в виде кода на C:

long *ip, buf, op;

fetch:
do {
buf = *op++;
control:
} while (!buf);
op = (buf >>= 4) & 0xf;
switch(op) {
:
}
goto control;
1

Другие решения

Вы должны быть в состоянии сделать это:

fetch:
asm("afetch: mov(%r8), %r9");
...
asm("jz afetch");

В качестве альтернативы, поместив этикетку в отдельный asm("afetch:"); должно работать так же. Обратите внимание на другое имя, чтобы избежать конфликтов — я не совсем уверен, что это необходимо, но я подозреваю, что это так.

0

По вопросам рекламы [email protected]