Получение значений регистра x64 с помощью встроенного asm - PullRequest
0 голосов
/ 24 апреля 2018

Мне было интересно, есть ли способ, который позволил бы мне указывать в качестве выходных операндов что-либо кроме eax, ebx, ecx и edx.

Допустим, я хочу поместить содержимое r8 в переменную. Можно ли написать что-то вроде этого:

  __asm__ __volatile__ (""  
                        :"=r8"(my_var) 
                        : /* no input */                             
                        );            

Ответы [ 2 ]

0 голосов
/ 24 апреля 2018

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

GNU C имеет ограничения специфического регистра только для оригинального 8регистры, как "=S"(rsi).Для r8..r15 единственным вариантом (во избежание необходимости инструкции mov внутри оператора asm) является переменная register-asm.

 register long long my_var __asm__ ("r8");
 __asm__ ("" :"=r"(my_var));               // guaranteed that r chooses r8

Возможно, вы захотите использовать дополнительный ввод / выводограничение для управления , где вы выбираете значение r8.(Например, "+rm"(some_other_var) сделает этот оператор asm частью цепочки зависимостей данных в вашей функции, но это также предотвратит постоянное распространение и другие оптимизации.) asm volatile может помочь в управлении упорядочением, но это не гарантируется.


Это иногда работает, чтобы опустить оператор __asm__ ("" :"=r"(my_var));, используя регистр local в качестве операнда, но он гарантированно сработает, если вы его используете: https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html#Local-Register-Variables. (И посмотрите обсуждение в комментариях к предыдущей версии этого ответа, в котором предлагалось, что вы можете пропустить эту часть.) Это не делает ваш код медленнее, поэтому не пропускайте эту часть, чтобы убедиться, что ваш код в целом безопасен.

Единственное поддерживаемое использование этой функции - указание регистров для операндов ввода и вывода при вызове Extended asm (см. Extended Asm).Это может быть необходимо, если ограничения для конкретной машины не обеспечивают достаточного контроля для выбора желаемого регистра.Чтобы ввести операнд в регистр, создайте локальную переменную и укажите имя регистра после объявления переменной.Затем используйте локальную переменную для операнда asm и укажите любую букву ограничения, которая соответствует регистру

PS Это расширение GCC, которое может быть не переносимым, но должно быть доступно на всех компиляторах, поддерживающих GNU Cвстроенный синтаксис asm.

gcc вообще не имеет ограничений на конкретные регистры для некоторых архитектур, таких как ARM, так что этот метод является единственным способом для редких случаев, когда вы хотите принудительно использовать определенные регистры для операндов ввода или вывода.


Пример:

int get_r8d(void) { 
     register long long my_var __asm__ ("r8");
     __asm__ ("" :"=r"(my_var));               // guaranteed that r chooses r8
     return my_var * 2;         // do something interesting with the value
}

, скомпилированный с gcc7.3 -O3 в проводнике компилятора Godbolt

get_r8d():
    lea     eax, [r8+r8]        # gcc can use it directly without a MOV first
    ret
0 голосов
/ 24 апреля 2018

Это должно быть возможно, исходя из ответа здесь: https://stackoverflow.com/a/43197401/3569229

#include <stdint.h>

uint64_t getsp( void )
{
    uint64_t sp;
    asm( "mov %%r8, %0" : "=rm" ( sp ));
    return sp;
}

Вы можете найти список имен регистров здесь: https://www3.nd.edu/~dthain/courses/cse40243/fall2015/intel-intro.html

Таким образом, ваш код выше будет изменен на:

__asm__ __volatile__ ("mov %%r8, %0"  
                        :"=rm"(my_var) 
                        : /* no input */                             
                        );            
...