Недавно эта функция rip_rel_ptr
была добавлена в ядро Linux.
https://elixir.bootlin.com/linux/latest/source/arch/x86/include/asm/asm.h#L118.
Я могу скомпилировать ядро, но когда я копирую эту функцию себе,
static inline
__attribute__((__always_inline__))
__attribute__((__pure__)) void *rip_rel_ptr(void *var)
{
asm("leaq %c1(%%rip), %0" : "=r"(var) : "i"(var));
return var;
}
#define RIP_REL_REF(var) (*(typeof(&(var)))rip_rel_ptr(&(var)))
int x;
int main(void)
{
RIP_REL_REF(x);
return 0;
}
Я вижу эту ошибку:
a.c: In function ‘main’:
a.c:8:2: warning: ‘asm’ operand 1 probably does not match constraints
8 | asm("leaq %c1(%%rip), %0" : "=r"(var) : "i"(var));
| ^~~
a.c:8:2: error: impossible constraint in ‘asm’
Не могу понять, почему оно компилируется в ядро на одной машине, но не может скомпилироваться отдельно.
Присмотревшись более внимательно к тому, как вы его используете, уверены ли вы, что код ядра использует этот макрос для автоматического хранения (нестатические локальные переменные)? Адрес локального объекта не является константой времени сборки, даже относительно .text
. Я ожидаю, что это будет работать с глобальной переменной или static
переменной, адрес которой можно получить с помощью LEA, относительного RIP.
Ну, AFAIK, для x86 только код в сжатом ядре компилируется как позиционно-независимый, а остальной - нет.
Я вижу аналогичную ошибку с глобальной переменной. Я отредактирую вопрос, чтобы переместить переменную наружу.
Похоже, вам нужно скомпилировать как минимум -O1
оптимизаций и глобальную переменную.
@MichaelPetch: О да, это имеет смысл, вам нужно постоянное распространение через функцию arg void *var
к оператору asm
. always_inline
не мешает параметрам функции быть реальными переменными, которые (в режиме отладки) действительно существуют со своим собственным адресом. (Почему этот класс-оболочка C++ не встраивается? - встраивается да, нет)
Это верно. Спасибо @MichaelPetch -O1
исправил проблему.
Вы уверены, что код ядра использует этот макрос для автоматического хранения (нестатические локальные переменные)? Адрес локального объекта в стеке не является константой времени сборки (ни абсолютной, ни относительной .text
).
Я ожидаю, что это будет работать с глобальной переменной или static
, поскольку ее адрес можно получить с помощью LEA, относительного RIP. Даже при использовании ASLR расстояние между .text
и статическим хранилищем (.data
, .bss
, .rodata
) фиксируется во время соединения.
Это также работает только при включенной оптимизации; вам нужно постоянное распространение через функцию arg void *var
в оператор asm. always_inline
не мешает параметрам функции быть реальными переменными, которые (в -O0
«отладочных» сборках) действительно существуют со своим собственным адресом. (Почему этот класс-оболочка C++ не встраивается? - встраивается да, оптимизирован нет)
IDK, если это важно, но ядро скомпилировано с
-mcmodel=kernel
; программы пользовательского пространства компилируются с-fPIE
(по умолчанию). Я не уверен, что сборки ядра также используют-fPIE
, но, вероятно, да, потому что ASLR ядра — это вещь.