MSVC: чтение конкретного 64- или 32-битного регистра (например, R10) в 64-битном коде? - PullRequest
0 голосов
/ 14 января 2019

Можно ли с помощью MSVC прочитать конкретный 64 (или 32) битный регистр непосредственно в обычной функции C ++?

Например, можно ли как-то прочитать содержимое r10 через какие-либо встроенные функции или что-то подобное?


Для контекста:

Я реализую функцию с переменным числом (давайте назовем ее my_func), которая должна переадресовать ее вызов другой функции с переменным числом аргументов и добавить еще один аргумент по пути (ID, если хотите, подойдет любой числовой тип - a 16, 32 или 64-битное целое число, например, не имеет большого значения).

Мне нужно выполнить пересылку как можно меньше инструкций, поэтому я не могу обработать список переменных в исходной функции и просто переслать va_list или что-то подобное.

Итак, я реализовал my_func в сборке:

; This function needs to be as compact as possible
my_func PROC
  ; assume 123 is the ID to be passed along with the arguments that my_func is called with
  mov r10, 123 
  jmp address_of_the_real_target_function
my_func

Я просто перехожу к целевой функции и передаю идентификатор в отдельный регистр - в данном случае R10.

ARG* the_real_target_function(ARG* arg0, ...)
{
    auto id = ReadRegister();
    // ... do stuff ...
}

Пока это работает хорошо - единственная неприятность в том, что мне понадобилась другая вспомогательная функция сборки для чтения R10 обратно в правильную функцию C ++,

ReadRegister PROC
  mov rax, r10
  ret
ReadRegister ENDP

, что немного раздражает, так как этот вызов не будет встроен.

Отсюда вопрос - есть ли способ прочитать этот регистр непосредственно в C ++?

(В противном случае я думал о том, чтобы, возможно, использовать регистры SSE, которые должны быть читаемы через встроенные функции - но любопытно, если есть способ сделать это только с 64- или 32-битными регистрами)

Спасибо

-

edit: я считаю, что не является дубликатом связанной темы. Перечисленные здесь решения относятся только к другим компиляторам или, в случае MSVC, только 32-разрядные (встроенная сборка не поддерживается в x64)

-

edit 2: Для получения дополнительной информации о том, почему я пытаюсь это сделать.

Этот индекс предназначен для добавления в Excel (который будет содержать плагины и, в основном, отображать их функции в Excel).

Чтобы зарегистрировать функцию в Excel, мне нужно привязать ее к определенной функции, экспортируемой моей DLL. Я не знаю заранее (= во время компиляции), сколько или какие функции плагина должны быть зарегистрированы и вызваны. Поэтому мне нужно реализовать множество экспортируемых функций - тысячи. Достаточно всегда иметь регистрационные слоты для всех доступных плагинов.

Для того, чтобы контролировать общий размер DLL, мне нужно, чтобы зарегистрированные функции были очень тонкими и в идеале были бы способны работать с переменными аргументами (поскольку я не знаю, какую форму имеют функции плагина в время компиляции и из-за нехватки места я хочу избежать создания обратных вызовов для любого возможного количества аргументов)

И для еще большего удовольствия, он должен работать в x64 и x86 - хотя в последнем случае функция вызывается Excel через соглашение stdcall, поэтому обычные C ++ variadic args не будут работать. Но, по крайней мере, во время выполнения я могу узнать количество (и тип) аргументов, переданных функции, поэтому я должен иметь возможность обрабатывать стек самостоятельно.

Итак, моя идея состоит в том, чтобы иметь эти тонкие батутные функции, которые будут перенаправлять все аргументы, плюс их ID, в некоторый центральный обработчик (как указано выше в X64; и через стек в X86).

Затем обработчик приводит все в порядок - то есть создает некоторый стандартизированный итератор для аргументов, вызывает фактическую функцию плагина, зарегистрированную через этот идентификатор и т. Д.

1 Ответ

0 голосов
/ 14 января 2019
Переменная

static thread_local займет всего несколько инструкций, поэтому она не такая тонкая, как вы могли бы пожелать. Все же это было бы полностью портативно.

Есть менее портативный, но более эффективный способ обучения. Обратите внимание на произвольный слот данных в TEB . Так что __readfsdword(0x14) / __writefsdword(0x14) на x86 и __readgsqword(0x28) / __writegsqword(0x28) на x64 могут сделать этот трюк. Если, ну, никто другой не использует такое же дополнительное пространство для других целей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...