Встроенная сборка не дает желаемого результата с помощью clang - PullRequest
1 голос
/ 14 июля 2020

Я использую встроенную сборку x86_64 с clang. Я хочу, чтобы сборка точная была скомпилирована в мой двоичный файл, который я указываю в исходном коде, но по какой-то причине clang продолжает ее изменять. Это происходит только тогда, когда я использую сборку в стиле AT&T G CC, этого не происходит с MSV C __asm Я хочу использовать сборку в стиле AT&T, потому что остальная часть моего кода много использует стиль AT&T и я хочу, чтобы все было последовательно. Вот как объявлен мой ассемблерный код:

__attribute__((naked)) void XxInternalOperation()
{
    asm volatile("mov %%rcx, %%rax\n\t"
        "mov %0, %%r11\n\t"
        "jmpq *%%r11"
        :
        : "r" (jumpAddrAbsolute)
        : "r11");
}

Я хочу, чтобы мой ассемблерный код представлял этот код Intel:

mov rax, rcx
mov r11, jmpAddrAbsolute ; <-- this is an unsigned long long variable
jmp r11

Но быстрая разборка в IDA показывает кое-что еще:

mov rax, cs:jumpAddrAbsolute
mov rax, rcx
mov r11, rax
jmp r11

Есть ли способ получить именно тот код сборки, который мне нужен?

1 Ответ

2 голосов
/ 14 июля 2020

Clang не «меняет» вашу сборку. Он делает именно то, что вы его просите, а именно: он выбирает регистр (это то, что означает ограничение r) и заменяет его %0. Обратите внимание, что этот регистр также может быть rax, и в этом случае ваш код не будет работать. Если вы хотите, чтобы clang выбирал операнд памяти, используйте вместо этого ограничение m. См. руководство по g cc для получения подробной информации о встроенной сборке в стиле g cc. Вот пример:

extern unsigned long long jumpAddrAbsolute;

__attribute__((naked)) void XxInternalOperation()
{
    asm volatile("mov %%rcx, %%rax\n\t"
        "mov %0, %%r11\n\t"
        "jmpq *%%r11"
        :
        : "m" (jumpAddrAbsolute)
        : "r11", "rax");
}

Это компилируется в:

movq    %rcx, %rax
movq    jumpAddrAbsolute(%rip), %r11
jmpq    *%r11

, что кажется тем, что вам нужно.

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

Обратите внимание также, что компилятор может решить встроить XxInternalOperation, и в этом случае ваш косвенный переход будет иметь непреднамеренный побочный эффект выполнения хвостового вызова в звонящий. Чтобы избежать этого сценария, подумайте о том, чтобы пометить функцию как noinline.

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

...