Я играю со встроенной сборкой в 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;
Обратите внимание на следующий комментарий в документации 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;
Вы должны быть в состоянии сделать это:
fetch:
asm("afetch: mov(%r8), %r9");
...
asm("jz afetch");
В качестве альтернативы, поместив этикетку в отдельный asm("afetch:");
должно работать так же. Обратите внимание на другое имя, чтобы избежать конфликтов — я не совсем уверен, что это необходимо, но я подозреваю, что это так.