2015-12-29 5 views
4

Гарантировано ли безопасное/переносное использование адреса параметра функции в компиляторе, совместимом с C89/C99?C адрес параметра функции?

В качестве примера, AAPCS для 32-разрядной ARM использует регистры r0-r3 для передачи параметров, если параметры функции соответствуют определенным требованиям размера и выравнивания. Я бы предположил, что использование адреса параметра, прошедшего через регистр, приведет к неожиданным результатам, но я проверил тест на компиляторе ARM, который я использую, и, похоже, он переместит эти параметры в стек, если код пытается ссылаться на адреса этих параметров. Хотя это будет выглядеть безопасно в моем конкретном приложении, мне интересно, гарантировано ли это в архитектуре (с компилятором, совместимым с ANSI/ISO), который может напрямую использовать регистры для передачи параметров функции.

Знают ли стандарты это поведение?

+3

Это разрешено по стандарту ISO C –

+0

Что такое M.M. сказал. Мне более любопытно, как бы код вызова *, который, возможно, находится в отдельном исходном файле и скомпилирован отдельно, знает, когда нужно проходить по регистру или по стеку. Или ARM всегда принимает пропуск по регистру, когда требования к размеру/выравниванию удовлетворяются сигнатурой функции (а вызываемый код заботится о переходе в стек)? – selbie

+0

Аргументы передаются через соответствующие регистры в соответствии с ABI. Аргументы, адрес которых берется внутри тела функции, затем переносятся в автоматическое хранилище (aka * в стеке *). – chqrlie

ответ

7

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

Как правило, у компилятора есть проход, где он проверяет, какие локальные переменные и параметры являются операндами для унарных операторов &. Затем их копируют в подходящую часть ОЗУ, когда это необходимо. Вызывающее соглашение не влияет на это.

+1

Второй абзац технически корректен для многих реализаций и имеет смысл добавить сюда. Однако следует подчеркнуть, что передача аргумента и подробное описание того, как выполняется адрес, не покрывается стандартом C. Существуют архитектуры, которые позволяют получить доступ к регистрам CPU через чтение обычной памяти или которые даже не используют регистры для передачи аргументов (некоторые даже не имеют доступных регистров) и т. Д. – Olaf

+0

@Olaf Я не знаю, почему вам нужно подчеркнуть это. Разве формулировка «Вообще ...» не ясно, что существуют платформы, на которых механизм отличается? И даже на платформах, которые регистрируют регистр в памяти, по крайней мере, если адрес передается другой функции, он не может указывать на регистр, поскольку вызывающий может решить использовать этот регистр для своей собственной цели. – fuz

+0

Я пытался подчеркнуть, что стандарт C не предусматривает его. «Вообще» сомнительно, так как это вопрос платформы, и есть некоторые платформы, которые не ведут себя так. Я бы не поставил, что имеет больше реализаций, имея в виду множество архитектур процессоров (не для того, чтобы получить доступ к встроенному миру, который только начинает обтекаться Cortex-M - будь то хорошо или плохо). Если такой адрес с псевдонимом передается, это другой вопрос и требует других мер. – Olaf

Смежные вопросы