встроенный синтаксис AT & T asm для непосредственного использования кода операции вместо мнемоники - PullRequest
0 голосов
/ 05 сентября 2018

По несчастным причинам, в которые я не могу войти, я должен поддержать древнего ассемблера, у которого нет отображения для нужной мне мнемоники.

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

Есть ли у кого-нибудь справка о том, как это сделать с помощью встроенного синтаксиса AT & T в GCC.

Ответы [ 2 ]

0 голосов
/ 05 сентября 2018

Попробуйте это:

long result;
char success = 0; /* make sure we don't get surprised by setc only writing 8 bits */

/* "rdrand %%rax ; setc %b1" */
asm volatile (".byte 0x48, 0x0f, 0xc7, 0xf0; setc %b1" : "=a"(result), "=qm"(success) :: "cc");

Ограничение a заставляет компилятор использовать регистр rax для result. Это столь же общее, как это происходит, не будучи противным. Я предлагаю вам добавить тест настройки, чтобы проверить, понимает ли ассемблер rdrand и использовать этот код:

long result;
char success = 0;

#ifdef HAVE_RDRAND
asm volatile ("rdrand %0; setc %b1" : "=r"(result), "=qm"(success) :: "cc");
#else
asm volatile (".byte 0x48, 0x0f, 0xc7, 0xf0; setc %b1" : "=a"(result), "=qm"(success) :: "cc");
#endif

Хотя может быть незначительное снижение производительности при принудительном использовании компилятором регистра rax, если ассемблер не понимает rdrand, он намного превосходит сложные клуджи, необходимые для использования любого регистра.

0 голосов
/ 05 сентября 2018

К счастью rdrand принимает только один аргумент, и это регистр. Таким образом, вам нужно охватить лишь несколько случаев, если вы хотите, чтобы компилятор мог свободно выбирать. Осторожно, это все еще довольно некрасиво:)

inline int rdrand()
{
    int result;
    __asm__ __volatile__ (
        ".byte 0x0f, 0xc7\n\t"
        ".ifc %0, %%eax\n\t"
        ".byte 0xf0\n\t"
        ".else\n\t"
        ".ifc %0, %%ebx\n\t"
        ".byte 0xf3\n\t"
        ".else\n\t"
        ".ifc %0, %%ecx\n\t"
        ".byte 0xf1\n\t"
        ".else\n\t"
        ".ifc %0, %%edx\n\t"
        ".byte 0xf2\n\t"
        ".else\n\t"
        ".ifc %0, %%esi\n\t"
        ".byte 0xf6\n\t"
        ".else\n\t"
        ".ifc %0, %%edi\n\t"
        ".byte 0xf7\n\t"
        ".else\n\t"
        ".ifc %0, %%ebp\n\t"
        ".byte 0xf5\n\t"
        ".else\n\t"
        ".error \"uknown register\"\n\t"
        ".endif\n\t"
        ".endif\n\t"
        ".endif\n\t"
        ".endif\n\t"
        ".endif\n\t"
        ".endif\n\t"
        ".endif\n\t"
    : "=R" (result) : : "cc");

    // "=R" excludes r8d..r15d in 64-bit mode
    return result;
}

Для 64-битного размера операнда вам понадобится префикс REX.W (0x48), но ограничение "=R" вместо "=r" позволит избежать использования других битов, установленных в Префикс REX.

Обратите внимание, что rdrand также использует флаг переноса, обработка которого оставлена ​​в качестве упражнения для читателя. gcc6 может использовать операнды вывода флага, что более эффективно, чем setcc.

...