архитектура — C ++ (вложенные) инструкции вызова функций — регистры

В C ++ FAQ:

Предполагая типичную реализацию C ++, которая имеет регистры и стек,
регистры и параметры записываются в стек непосредственно перед
вызовите g (), тогда параметры будут считаны из стека внутри g ()
и снова прочитайте, чтобы восстановить регистры, пока g () возвращается к f ().

относительно вызова вложенной функции

void f()
{
int x = /*...*/;
int y = /*...*/;
int z = /*...*/;
...code that uses x, y and z...
g(x, y, z);
...more code that uses x, y and z...
}

1 / Все ли реализации C ++ с регистрами и стеком? Означает ли это: реализация зависит от архитектуры компилятора / процессора / компьютера?

2 / Какова последовательность инструкций (без языка ассемблера, просто большая картинка), когда я звоню f() ? Я читал разные вещи по этой теме, а также я не помню, чтобы регистры упоминались, а только в стеке.

3 / какие дополнительные особенности / моменты следует подчеркнуть, когда вы имеете дело с вложенными функциями?

Спасибо

3

Решение

Для номера 2 это зависит от многих вещей, включая компилятор и платформу. Обычно называются различные способы передачи и возврата аргументов в функции соглашения о вызовах. статья Соглашения о вызовах на платформе x86 вдаваясь в некоторые подробности о последовательности операций, вы можете увидеть, насколько уродливым и сложным он становится с этой небольшой комбинацией платформ и компиляторов, что, скорее всего, является причиной того, что вы слышали все виды различных сценариев, Ген на соглашениях о вызовах функций. охватывает более широкий набор сценариев, включая 64 bit платформы, но труднее читать. Это становится еще сложнее, потому что gcc не может на самом деле push а также pop стек, но непосредственно манипулировать указателем стека, мы можем увидеть пример этого, хотя и в сборке Вот. Трудно обобщить соглашения о вызовах, если число аргументов достаточно мало, многие соглашения о вызовах могут избежать использования stack вообще и буду использовать registers исключительно.

Что касается числа 3Вложенные функции ничего не меняют, они просто повторяют процедуру снова для следующего вызова функции.

Что касается числа 1 Как указал Шон .Net компилирует в байтовый код с выполняет все свои операции в стеке. Страница Википедии на Общий промежуточный язык есть хороший пример.

x86-64 ABI документ Это еще один отличный документ, если вы хотите понять, как работает конкретное соглашение о вызовах. Figure 3.5 and 3.6 аккуратны, так как они дают хороший пример функции с множеством параметров и того, как каждый параметр передается с использованием комбинации general purpose registers, floating point registers и stack, Такая симпатичная диаграмма — редкая находка при просмотре документов, которые охватывают соглашения о вызовах.

3

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

1. Хотя реализации регистра / стека являются наиболее распространенными базовыми реализациями компилятора C ++, ничто не мешает вам использовать другую архитектуру. Например, вы можете написать компилятор для генерации Java-байт-кода или .NET-байт-кода, и в этом случае у вас будет стековый компилятор C ++.

2. Когда вы вызываете f (), типичный подход:

  • Вставьте адрес возврата в стек и перейдите к f ()

  • В ф ():

  • Выделите место для локалей x, y и z. Обычно это делается в стеке. Взгляни на Эта статья на стеки вызовов.

  • Когда вы доберетесь до g (x, y, z), компилятор сгенерирует код для помещения значений в стек, получая доступ к их значениям в кадре стека функции f (). Обратите внимание, что C / C ++ изменяет параметры справа налево.

  • Когда вы дойдете до конца f (), компилятор вставляет return инструкции. Вершина стека имеет адрес для возврата (он был передан до вызова f ())

3. Во вложенных функциях нет ничего особенного, так как все соответствует одному базовому шаблону:

  • Для вызова функции — нажмите параметры и вызовите функцию.
  • Внутри функции — выделить место для локальных переменных в стеке

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

ПРИМЕЧАНИЕ. Хотя передача параметров стеком, безусловно, является наиболее распространенным подходом, существуют и другие. Взгляните на эту статью на зарегистрировать окна если вы заинтересованы в том, чтобы узнать больше.

1