Получение адреса аргумента, переданного в регистр

В C ++ с передачей по значению вызывающая сторона создает копию, которую использует вызываемый. В x64 ABI некоторые аргументы передаются в регистрах. Регистры не имеют адресов.

Итак, предположим, у меня есть следующий класс:

class Self_Pointer
{
Self_Pointer* self;
Self_Pointer(const Self_Pointer& obj) : self(this) {}
}

При передаче в качестве аргумента он принимает указатель на себя. И теперь у меня есть эта функция:

f(Self_Pointer x) {}

f() принимает значение Self_Pointer, переданное в регистр в соответствии с соглашением о вызовах. Вызывающая сторона f() пришлось бы создать копию в реестре. Таким образом, вызывающая сторона запускает конструктор для Self_Pointer, расположенного в регистре. Однако регистры не имеют адресов, поэтому было бы невозможно запустить конструктор. Как решить эту дилемму?

[Редактировать: исправил ctor класса к ctor копии согласно ответу Стива Джессопа.]

0

Решение

Во-первых, копия Self_Pointer не указывает на себя. Он указывает на оригинал, потому что сгенерированный компилятором конструктор копирования копирует значение self от оригинала до копии.

Итак, когда вы передаете объект с копией f, по факту x не указывает на себя.

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

Для другого примера рассмотрим:

void foo(int i) {
std::cout << &i << '\n';
}

Опять же, реализация обязана организовать это i имеет адрес. Если он передается в регистр (и, как у регистров x64, нет адресов на этом конкретном оборудовании), то функция foo должен пролиться i в стек. Тогда у него будет адрес, как и у любой другой переменной стека.

2

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

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

2

Нет, ты не можешь. Получаемый вами адрес всегда является виртуальным адресом ОЗУ. Вы не можете получить доступ к адресу реестра непосредственно в C ++.

0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector