Загрузить 64-битную целочисленную константу через расширенное ограничение asm GNU?

Я написал этот код в Clang-совместимом «GNU extended asm»:

namespace foreign {
extern char magic_pointer[];
}

extern "C" __attribute__((naked)) void get_address_of_x(void)
{
asm volatile("movq %[magic_pointer], %%rax\n\t""ret": : [magic_pointer] "p"(&foreign::magic_pointer));
}

Я ожидал, что он скомпилируется в следующую сборку:

_get_address_of_x:
## InlineAsm Start
movq    $__ZN7foreign13magic_pointerE, %rax
ret
## InlineAsm End
ret  /* useless but I don't think there's any way to get rid of it */

Но вместо этого я получаю эту «ерунду»

_get_address_of_x:
movq    __ZN7foreign13magic_pointerE@GOTPCREL(%rip), %rax
movq    %rax, -8(%rbp)
## InlineAsm Start
movq -8(%rbp), %rax
ret
## InlineAsm End
ret

Видимо, Clang присваивает значение &foreign::magic_pointer в %rax (что смертельно для naked функция), а затем далее «пролить» его на кадр стека, который даже не существовать, все, так что он может снова выполнить его в блоке встроенного ассемблера.

Итак, как я могу заставить Clang генерировать именно тот код, который я хочу, не прибегая к ручному определению имен? Я имею в виду, я мог бы просто написать

extern "C" __attribute__((naked)) void get_address_of_x(void)
{
asm volatile("movq  __ZN7foreign13magic_pointerE@GOTPCREL(%rip), %rax\n\t""ret");
}

но я действительно не хочу этого делать, если есть какой-то способ помочь.

Прежде чем нажать на "p"Я бы попробовал "i" а также "n" ограничения; но они не работают должным образом с 64-битными операндами-указателями. Clang продолжал давать мне сообщения об ошибках о невозможности выделить операнд для %flags зарегистрироваться, что, кажется, что-то сумасшедшее пошло не так.


Для тех, кто заинтересован в решении «проблемы XY» здесь: я действительно пытаюсь написать гораздо более длинную сборочную заглушку, которая вызывает другую функцию foo(void *p, ...) где аргумент p устанавливается в значение этого магического указателя, а остальные аргументы устанавливаются на основе исходных значений регистров ЦП в момент ввода этой заглушки сборки. (Следовательно, naked функция.) Произвольная политика компании не позволяет просто написать эту чертову вещь в .S файл для начала; и кроме того, я действительно было бы нравится писать foreign::magic_pointer вместо __ZN7foreign...etc..., В любом случае, это должно объяснить, почему выкладывание временных результатов в стек или регистры является строго вербальным в этом контексте.


Возможно, есть какой-то способ написать

asm volatile(".long %[magic_pointer]" : : [magic_pointer] "???"(&foreign::magic_pointer));

заставить Clang вставить именно то перемещение, которое я хочу?

2

Решение

Я думаю, что это то, что вы хотите:

namespace foreign {
extern char magic_pointer[];
}

extern "C" __attribute__((naked)) void get_address_of_x(void)
{
asm volatile ("ret" : : "a"(&foreign::magic_pointer));
}

В этом контексте «а» является ограничением, которое указывает, что %rax должен быть использован. Затем Clang загрузит адрес magic_pointer в %rax в подготовке к выполнению вашего встроенного асма, что все, что вам нужно.

Это немного хитроумно, потому что оно определяет ограничения, на которые нет ссылок в тексте asm, и я не уверен, что это технически разрешено / четко определено — но это работает на последнем кланге.

На clang 3.0-6ubuntu3 (потому что я ленивый и использую gcc.godbolt.org), с -fPIC, это asm вы получаете:

get_address_of_x:                       # @get_address_of_x
movq    foreign::magic_pointer@GOTPCREL(%rip), %rax
ret
ret

И без -fPIC:

get_address_of_x:                       # @get_address_of_x
movl    foreign::magic_pointer, %eax
ret
ret
2

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

ОП здесь.

Я просто написал помощника extern "C" функция, чтобы вернуть магическое значение, а затем вызвать эту функцию из моего кода сборки. Я все еще думаю, что Clang должен каким-то образом поддерживать мой оригинальный подход, но главная проблема с этим подходом в моем реальном случае заключалась в том, что он не масштабировался до x86-32. На x86-64 загрузка произвольного адреса в %rdx может быть сделано в одной инструкции с %rip-родственник mov, Но на x86-32 загрузка произвольного адреса с -fPIC превращается просто в тонна кода, .indirect_symbol директивы, два доступа к памяти … Я просто не хотел попытка писать все это от руки. Так что мой код окончательной сборки выглядит так

asm volatile(
"...save original register values...;""call  _get_magic_pointer;""movq  %rax, %rdx;""...set up other parameters to foo...;""call  _foo;""...cleanup...");

Проще и чище. 🙂

1

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