Соглашение о вызовах

редактировать

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

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

конкретного языка.

Содержание

  • 1 Варианты
    • 1.1 Вариант компилятора
    • 1.2 Вариант архитектуры
      • 1.2.1 x86 (32-разрядный)
      • 1.2.2 ARM (A32)
      • 1.2.3 ARM (A64)
      • 1.2.4 PowerPC
      • 1.2.5 MIPS
      • 1.2.6 SPARC
      • 1.2.7 IBM System / 360 и последующие
      • 1.2.8 SuperH
      • 1.2.9 68k
      • 1.2.10 IBM 1130
  • 2 Рекомендации по реализации
    • 2.1 Потоковый код
    • 2.2 PL / I
  • 3 См. Также
  • 4 Ссылки
  • 5 Внешние ссылки

Варианты

Соглашения о вызовах могут отличаться:

  • Где размещаются параметры, возвращаемые значения и адреса возврата (в регистрах, в стеке вызовов , в сочетании обоих или в другом запоминающем устройстве y структур)
  • Порядок, в котором передаются фактические аргументы для формальных параметров (или части большого или сложного аргумента)
  • Как возвращаемое значение (возможно длинное или сложное) доставляется из вызываемый объект возвращается к вызывающему (в стеке, в регистре или в куче)
  • Как задача настройки и очистки после вызова функции разделяется между вызывающим и вызываемым
  • Передаются ли и как метаданные, описывающие аргументы
  • Где хранится предыдущее значение указателя кадра, которое используется для восстановления указателя кадра, когда процедура заканчивается (в в кадре стека или в каком-либо регистре)
  • Где размещаются любые ссылки статической области для нелокального доступа к данным подпрограммы (обычно в одной или нескольких позициях в кадре стека, но иногда в общем регистре или, для некоторых архитектур в регистрах специального назначения)
  • Способ распределения локальных переменных иногда также может быть частью соглашения о вызовах (когда вызываемый r выделяет для вызываемого)

В некоторых случаях различия также включают следующее:

  • Соглашения, по которым регистры могут напрямую использоваться вызываемым пользователем без сохранения (в противном случае они рассматриваются как деталь ABI )
  • Какие регистры считаются энергозависимыми и, если они непостоянны, их не нужно восстанавливать вызываемым пользователем (часто рассматривается как деталь ABI)

Вариант компилятора

Хотя некоторые языки программирования могут частично указывать это в спецификации языка или в основной реализации, в различных реализациях таких языков (т.е. разные компиляторы ) обычно могут по-прежнему использовать различные соглашения о вызовах, часто выбираемые. Причины этого - производительность, частая адаптация к соглашениям других популярных языков с техническими причинами или без них, а также ограничения или соглашения, налагаемые различными «вычислительными платформами ».

Вариант архитектуры

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

x86 (32-бит)

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

Пример вызова:

push EAX; передать некоторый байт толчка результата регистра [EBP + 20]; передать некоторую переменную памяти (синтаксис FASM / TASM) push 3; передать некоторый постоянный вызов calc; возвращенный результат теперь находится в EAX

Типичная структура вызываемого объекта: (некоторые или все (кроме ret) приведенных ниже инструкций могут быть оптимизированы с помощью простых процедур)

calc: push EBP; сохранить указатель старого кадра mov EBP, ESP; получить новый указатель кадра sub ESP, localsize; зарезервировать место в стеке для местных жителей.. ; произвести расчеты, оставить результат в EAX. mov ESP, EBP; свободное место для местных жителей поп EBP; восстановить старый указатель кадра ret paramsize; свободное пространство для параметров и возврат

ARM (A32)

Стандартное 32-битное соглашение о вызовах ARM выделяет 15 регистров общего назначения как:

  • r15: Программный счетчик (как согласно спецификации набора команд).
  • r14: регистр связи. Инструкция BL, используемая в вызове подпрограммы, сохраняет адрес возврата в этом регистре.
  • r13: указатель стека. Команды Push / Pop в рабочем режиме «Thumb» используют только этот регистр.
  • r12: Временный регистр вызова внутри процедуры.
  • r4 - r11: Локальные переменные.
  • от r0 до r3: значения аргументов, переданные подпрограмме, и результаты, возвращаемые подпрограммой.

Если тип возвращаемого значения слишком велик, чтобы поместиться в r0 - r3, или размер которого не может быть определен статически во время компиляции, то вызывающий должен выделить пространство для этого значения во время выполнения и передать указатель на это пространство в r0.

Подпрограммы должны сохранять содержимое от r4 до r11 и указатель стека (возможно, сохраняя их в стеке в прологе функции , затем используя их как рабочее пространство, а затем восстанавливая их из стек в эпилоге функции ). В частности, подпрограммы, которые вызывают другие подпрограммы, должны сохранять адрес возврата в регистре связи r14 в стек перед вызовом этих других подпрограмм. Однако таким подпрограммам не нужно возвращать это значение в r14 - им просто нужно загрузить это значение в r15, программный счетчик, чтобы вернуться.

Соглашение о вызовах ARM требует использования полного нисходящего стека.

Это соглашение о вызовах приводит к тому, что "типичная" подпрограмма ARM выполняет следующие действия:

  • В прологе нажмите r4 на r11 в стек, и поместите адрес возврата в r14 в стек (это можно сделать с помощью одной инструкции STM);
  • Скопируйте все переданные аргументы (в r0 на r3) в локальные временные регистры (от r4 до r11);
  • Назначьте другие локальные переменные оставшимся локальным временным регистрам (от r4 до r11);
  • Выполняйте вычисления и при необходимости вызывайте другие подпрограммы с использованием BL, предполагая, что от r0 до r3, r12 и r14 не будут сохранено;
  • Поместите результат в r0;
  • В эпилоге вытащите из стека с r4 по r11 и перенесите адрес возврата в программный счетчик r15. Это можно сделать с помощью одной инструкции LDM.

ARM (A64)

Соглашение о вызовах 64-битного ARM (AArch64 ) выделяет 31 регистр общего назначения как:

  • x31 (SP): указатель стека или нулевой регистр, в зависимости от контекста.
  • x30 (LR): регистр ссылки на процедуру, используемый для возврата из подпрограмм.
  • x29 (FP): Frame указатель.
  • x19 - x29: сохраненный вызываемый.
  • x18 (PR): регистр платформы. Используется для некоторых специальных целей, специфичных для операционной системы, или для дополнительного сохраненного регистром вызывающего абонента.
  • x16 (IP0) и x17 (IP1): временные регистры внутрипроцедурного вызова.
  • x9 до x15: локальные переменные, вызывающая сторона сохранена.
  • x8 (XR): адрес косвенного возвращаемого значения.
  • x0 до x7: значения аргументов, переданные в подпрограмму, и результаты, возвращаемые из подпрограммы.

Все регистры, начинающиеся с x, имеют соответствующий 32-битный регистр с префиксом w. Таким образом, 32-битный x0 называется w0.

PowerPC

Архитектура PowerPC имеет большое количество регистров, поэтому большинство функций могут передавать все аргументы в регистры для одноуровневых вызовов. Дополнительные аргументы передаются в стек, и пространство для аргументов на основе регистров также всегда выделяется в стеке для удобства вызываемой функции в случае использования многоуровневых вызовов (рекурсивных или иных) и необходимости сохранения регистров. Это также используется в вариативных функциях, таких как printf (), где к аргументам функции нужно обращаться как к массиву. Для всех процедурных языков используется единое соглашение о вызовах.

MIPS

O32 ABI является наиболее часто используемым ABI благодаря своему статусу исходного ABI System V для MIPS. Он строго основан на стеке, и для передачи аргументов доступны только четыре регистра $ a0- $ a3. Эта кажущаяся медлительность, наряду со старинной моделью с плавающей запятой только с 16 регистрами, способствовала распространению многих других соглашений о вызовах. ABI сформировался в 1990 году и никогда не обновлялся с 1994 года. Он определен только для 32-битных MIPS, но GCC создал 64-битный вариант под названием O64.

Для 64-битных версий. бит, чаще всего используется N64 ABI от Silicon Graphics. Наиболее важным улучшением является то, что теперь доступно восемь регистров для передачи аргументов; Это также увеличивает количество регистров с плавающей запятой до 32. Существует также версия ILP32 под названием N32, которая использует 32-битные указатели для меньшего кода, аналогично x32 ABI. Оба работают в 64-битном режиме ЦП.

Было предпринято несколько попыток заменить O32 32-битным ABI, больше напоминающим N32. Конференция 1995 года представила MIPS EABI, для которого 32-разрядная версия была очень похожей. EABI вдохновил MIPS Technologies на предложение более радикального ABI "NUBI", который дополнительно повторно использует регистры аргументов для возвращаемого значения. MIPS EABI поддерживается GCC, но не LLVM; ни один из них не поддерживает NUBI.

Для всех O32 и N32 / N64 адрес возврата сохраняется в регистре $ ra. Это автоматически устанавливается с использованием инструкций JAL(переход и ссылка) или JALR(регистр перехода и связи). Стек растет вниз.

SPARC

Архитектура SPARC, в отличие от большинства архитектур RISC, построена на окнах регистров. В каждом окне регистров есть 24 доступных регистра: 8 - это входящие регистры (% i0-% i7), 8 - это «локальные» регистры (% l0-% l7) и 8 - это регистры «выхода» (% о0-% о7). Регистры "in" используются для передачи аргументов вызываемой функции, и любые дополнительные аргументы должны быть помещены в стек . Однако вызываемая функция всегда выделяет пространство для обработки потенциального переполнения окна регистров, локальных переменных и (на 32-битном SPARC) возврата структуры по значению. Чтобы вызвать функцию, нужно поместить аргументы функции, которая должна быть вызвана, в регистры «out»; когда функция вызывается, регистры "out" становятся регистрами "in", а вызываемая функция получает доступ к аргументам в своих регистрах "in". Когда вызываемая функция завершает свою работу, она помещает возвращаемое значение в первый входной регистр, который становится первым выходным регистром, когда вызываемая функция возвращается.

Система System V ABI, которой следуют большинство современных Unix -подобных систем, передает первые шесть аргументов в регистры "in"% i0 через% i5, зарезервировав% i6 для указателя кадра и% i7 для адреса возврата.

IBM System / 360 и последующие

IBM System / 360 - это еще одна архитектура без аппаратного стека. Приведенные ниже примеры иллюстрируют соглашение о вызовах, используемое OS / 360 и его преемниками до введения 64-битной z / Architecture ; другие операционные системы для System / 360 могут иметь другие соглашения о вызовах.

Вызывающая программа:

LA 1, ARGS Загрузить адрес списка аргументов L 15, = A (SUB) Загрузить адрес подпрограммы BALR 14,15 Переход к вызываемой подпрограмме... ARGS DC A (FIRST) Адрес 1-го аргумента DC A (SECOND)... DC A (THIRD) + X'80000000 'Последний аргумент

Вызываемая программа:

SUB EQU * Это точка входа подпрограмма

Стандартная последовательность ввода:

USING *, 15 STM 14,12,12 (13) Сохранение регистров ST 13, SAVE + 4 Сохранение адреса сохраненной области вызывающего абонента LA 12, SAVE Chain saveareas ST 12, 8 (13) LR 13,12...

Стандартная последовательность возврата:

L 13, SAVE + 4 LM 14,12,12 (13) L 15, RETVAL BR 14 Return вызывающему SAVE DS 18F Savearea

Примечания:

  1. Инструкция BALRсохраняет адрес следующей инструкции (адрес возврата) в регистре, заданном первым аргументом - регистром 14 - и переходит ко второму адресу аргумента в регистре 15.
  2. Вызывающий передает адрес списка адресов аргументов в регистре 1. Последний адрес имеет старший бит, установленный на ind Отметьте конец списка. Это ограничивает программы, использующие это соглашение, до адресации 31-бит.
  3. Адрес вызываемой подпрограммы находится в регистре 15. Обычно он загружается в другой регистр, а регистр 15 не используется в качестве базовый регистр.
  4. Команда STMсохраняет регистры 14, 15 и 0–12 в 72-байтовой области, предоставленной вызывающей стороной, называемой областью сохранения, на которую указывает регистр 13. Вызываемый процедура предоставляет свою собственную область сохранения для использования вызываемыми ею подпрограммами; адрес этой области обычно сохраняется в регистре 13 на протяжении всей процедуры. Инструкции, следующие за STMобновляют прямую и обратную цепочки, связывая эту область сохранения с областью сохранения вызывающего абонента.
  5. Последовательность возврата восстанавливает регистры вызывающего абонента.
  6. Обычно используется регистр 15 для передачи возвращаемого значения.
  7. Статическое объявление области сохранения в вызываемой подпрограмме делает ее нереентерабельной и нерекурсивной ; программа с повторным входом использует динамическую область сохранения, полученную либо из операционной системы и освобождаемую при возврате, либо в памяти, передаваемой вызывающей программой.

В System / 390 ABI и z / Архитектура ABI, используемый в Linux:

  • Регистры 0 и 1 являются энергозависимыми
  • Регистры 2 и 3 используются для передачи параметров и возвращаемых значений
  • Регистры 4 и 5 также используются для передачи параметров
  • Регистр 6 используется для передачи параметров и должен быть сохранен и восстановлен вызываемым пользователем
  • Регистры с 7 по 13 предназначены для использования вызываемым пользователем и должны быть сохранены и восстановлены их
  • Регистр 14 используется для адреса возврата
  • Регистр 15 используется как указатель стека
  • Регистры с плавающей запятой 0 и 2 используются для передачи параметров и возврата значений
  • Регистры с плавающей запятой 4 и 6 предназначены для использования вызываемым пользователем и должны быть сохранены и восстановлены им
  • В z / Architecture регистры с плавающей запятой 1, 3, 5 и С 7 по 15 предназначены для использования вызываемым пользователем
  • Регистр доступа 0 зарезервирован для использования системой
  • Регистры доступа с 1 по 15 предназначены для использования вызываемым объектом

SuperH

РегистрWindows CE 5.0 gcc Renesas
R0Возвращаемые значения. Временно для расширения псевдо-инструкций сборки. Неявный источник / назначение для 8/16-битных операций. Не сохраняется.Возвращаемое значение, вызывающий сохраняетпеременные / временные. Не гарантируется
R1..R3Служит временными регистрами. Не сохранилось.Абонент сохранил царапину. Адрес структуры (сохранение вызывающего абонента по умолчанию)Переменные / временные. Не гарантируется
R4..R7Первые четыре слова целочисленных аргументов. Область построения аргументов предоставляет пространство, в которое могут попадать аргументы от R4 до R7. Не сохраняется.Передача параметров, вызывающий сохраняетаргументы. Не гарантировано.
R8..R13Служит как постоянные регистры. Сохранено.Вызываемый сохраняетпеременные / временные. Гарантированно.
R14Указатель кадра по умолчанию. (R8-R13 может также служить указателем кадра, а конечные процедуры могут использовать R1 – R3 как указатель кадра.) Сохраняется.Указатель кадра, FP, вызываемый объект сохраняетпеременные / временные. Гарантированно.
R15Служит указателем стека или постоянным регистром. Сохранено.Указатель стека, SP, вызываемый объект сохраняетуказатель стека. Гарантированно.

Примечание: «сохраненные» резервы для сохранения вызываемого абонента; то же самое и с «гарантированным».

68k

В Викиучебнике есть книга на тему: Сборка 68000

Наиболее распространенное соглашение о вызовах для Motorola серии 68000 :

  • d0, d1, a0 и a1 - временные регистры
  • Все остальные регистры сохраняются вызываемым
  • a6 - указатель кадра, который можно отключить с помощью параметра компилятора
  • Параметры помещаются в стек справа налево
  • Возвращаемое значение сохраняется в d0

IBM 1130

IBM 1130 было маленьким 16-битным словом -адресная машина. У него было всего шесть регистров плюс индикаторы состояния и не было стека. Регистры - это регистр адреса инструкции (IAR), накопитель (ACC), расширение накопителя (EXT) и три индексных регистра X1 – X3. Вызывающая программа отвечает за сохранение ACC, EXT, X1 и X2. Существуют две псевдооперации для вызова подпрограмм, CALLдля кодирования неперемещаемых подпрограмм, напрямую связанных с основной программой, и LIBFдля вызова подпрограмм перемещаемой библиотеки через вектор передачи. Обе псевдооперации разрешаются в машинную инструкцию Branch and Store IAR (BSI), которая сохраняет адрес следующей инструкции по ее эффективному адресу (EA) и выполняет переход к EA + 1.

Аргументы следуют за BSI‍ - «обычно это адреса аргументов из одного слова» - «вызываемая подпрограмма должна знать, сколько аргументов ожидать, чтобы она могла пропустить их при возврате. В качестве альтернативы аргументы можно передавать в регистрах. Функциональные подпрограммы возвращали результат в ACC для реальных аргументов или в области памяти, называемой псевдоаккумулятором вещественных чисел (FAC). Аргументы и адрес возврата были адресованы с использованием смещения значения IAR, хранящегося в первом местоположении подпрограммы.

* Пример подпрограммы 1130 ENT SUB Объявление «SUB» внешней точки входа SUB DC 0 Зарезервированное слово в точке входа, обычно кодируемое как «DC * - *» * Код подпрограммы начинается здесь * Если были аргументы, адреса могут загружаться косвенно из адреса возврата LDX I 1 SUB Загрузить X1 с адресом первого аргумента (например)... * Последовательность возврата LD RES Загрузить целочисленный результат в ACC * Если аргументы не были предоставлены, косвенный переход к сохраненному возврату адрес BI SUB Если аргументы не были предоставлены END SUB

Подпрограммы в IBM 1130, CDC 6600 и PDP-8 (все три компьютера были представлены в 1965 году) сохраняют адрес возврата в первом месте подпрограммы.

Соображения по реализации

Эту изменчивость необходимо учитывать при объединении модулей, написанных на нескольких языках, или при вызове операционной системы или библиотеки API с другого языка, кроме того, на котором они написаны; в этих случаях необходимо уделять особое внимание согласованию соглашений о вызовах, используемых вызывающим и вызываемым абонентами. Даже программа, использующая один язык программирования, может использовать несколько соглашений о вызовах, выбранных компилятором для оптимизации кода или указанных программистом.

Потоковый код

Потоковый код возлагает всю ответственность за настройку и очистку после вызова функции в вызываемом коде. Вызывающий код ничего не делает, кроме списка вызываемых подпрограмм. Это помещает весь код настройки функции и очистки в одно место - пролог и эпилог функции - а не во многие места, где функция вызывается. Это делает многопоточный код наиболее компактным соглашением о вызовах.

Потоковый код передает все аргументы в стеке. Все возвращаемые значения возвращаются в стек. Это делает наивные реализации медленнее, чем соглашения о вызовах, которые хранят больше значений в регистрах. Однако реализации потокового кода, которые кэшируют несколько верхних значений стека в регистрах, в частности адрес возврата, обычно работают быстрее, чем соглашения о вызове подпрограмм, которые всегда помещают адрес возврата в стек.

PL / I

Соглашение о вызовах по умолчанию для программ, написанных на языке PL / I, передает все аргументы по ссылке, хотя при желании могут быть указаны другие соглашения. Аргументы обрабатываются по-разному для разных компиляторов и платформ, но обычно адреса аргументов передаются через список аргументов в памяти. Может быть передан окончательный скрытый адрес, указывающий на область, содержащую возвращаемое значение. Из-за большого разнообразия типов данных, поддерживаемых PL / I, дескриптор данных также может быть передан для определения, например, длины символьных или битовых строк, размеров и границ массивов (допинговые векторы ) или макет и содержимое структуры данных . Фиктивные аргументы создаются для аргументов, которые являются константами или не согласуются с типом аргумента, который ожидает вызываемая процедура.

См. Также

  • значок Портал компьютерного программирования

Ссылки

Внешние ссылки

У Wikibook Embedded Systems есть страница по теме: Смешанное программирование на C и ассемблере
В Wikibook X86 Disassembly есть страница по теме: Соглашения о вызовах
Последняя правка сделана 2021-05-14 14:52:25
Содержание доступно по лицензии CC BY-SA 3.0 (если не указано иное).
Обратная связь: support@alphapedia.ru
Соглашение
О проекте