В общем, как я грущу target.def, когда прототип функции объявлен с помощью ( ,...) компилятор устанавливает дерево синтаксического анализа, помеченное флагом varargs и ссылками на типы именованных аргументов. Для строгого соответствия C каждый именованный аргумент должен получать любую дополнительную информацию, необходимую для настройки va_list, когда этот параметр является именованным полем va_start и в качестве возможного возврата в va_arg(), но большинство компиляторов просто генерируют эту информацию для последнего именованного аргумента. . Когда функция определена, ее генератор пролога отмечает, что был установлен флаг varargs, и добавляет код, необходимый для настройки любых скрытых полей, которые он добавляет к фрейму, который имеет известные смещения, на которые может ссылаться макрос va_start.
Когда он находит ссылку на эту функцию, он создает дополнительные деревья синтаксического анализа и генерации кода для каждого аргумента, представляющего ..., которые могут вводить дополнительные скрытые поля информации о типе времени выполнения, такие как границы массива, которые добавляются к настройкам полей для va_start. и va_arg для именованных аргументов. Это комбинированное дерево определяет, какой код генерируется для копирования значений параметров во фрейм, пролог устанавливает, что необходимо для va_start для создания va_list, начиная с произвольного или последнего именованного параметра, и каждый вызов va_arg() генерирует встроенный код, который ссылается на любые скрытые поля, специфичные для параметра, используемые для проверки во время компиляции ожидаемого возврата, являются назначением, совместимым с использованием компилируемого выражения, и выполняют любые необходимые продвижения/приведения аргументов. Сумма размеров значений именованных полей и размеров скрытых полей определяет, какое значение компилируется после вызова или в эпилоге функции для моделей очистки вызываемого объекта для корректировки кадра по возвращении.
Каждый из этих шагов имеет зависимости от процессора и соглашения о вызовах, инкапсулированные в файлы config/proc/proc.c и proc.h, которые переопределяют упрощенные определения по умолчанию va_start() и va_arg(), предполагающие, что каждый аргумент имеет фиксированный выделенный размер. некоторое расстояние выше первого именованного аргумента в стеке. Для некоторых платформ или языков кадры параметров, реализованные как отдельные malloc(), более желательны, чем стек фиксированного размера. Также обратите внимание, что эти варианты использования не являются потокобезопасными; небезопасно передавать ссылку va_list в другой поток без неуказанных средств обеспечения того, чтобы кадр параметра не стал недействительным из-за возврата функции или прерывания потока.
person
M. Ziegast
schedule
10.06.2018
va_arg
набор функций для переменных аргументов может различаться в зависимости от архитектуры машины и соглашений о вызовах, ABI, которые используются с конкретными процессорами. Современные процессоры с большим количеством доступных регистров, чем в старой архитектуре x86, позволяют передавать аргументы как в регистрах, так и в стеке. - person Richard Chambers   schedule 15.03.2018