Wiki

Интерфейс вывода в GNU CC

Обычно GNU CC конфигурируется для использования того же самого соглашения о вызове функций, которое обычно используется в целевой системе. Это выполнено при помощи макрокоманд с машинным описанием (* См.: Целевые макрокоманды::.).

Однако, возврат значений структуры и объединения выполнен по-другому на некоторых целевых машинах. В результате, функции, скомпилированные PCC, возвращающие такие типы, не могут вызываться из кода, скомпилированного GNU CC, и наоборот. Но это не вызывает проблему часто, потому что мало библиотечных подпрограмм UNIX возвращает структуры или объединения.

GNU CC код возвращает структуры и объединения длины 1, 2, 4 или 8 байт в тех же самых регистрах, которые используются для возвращения значения " int " или " double ".( GNU CC обычно распределяет переменные таких типов тоже в регистрах.) Структуры и объединения других размеров возвращаются путем записи их по адресу, переданному вызывающей подпрограммой (обычно в регистре). Макрокоманды с машинным описанием " STRUCT_VALUE " и " STRUCT_INCOMING_VALUE " сообщают GNU CC, куда передать этот адрес.

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

На некоторых целевых машинах, типа RISC машин и 80386, стандартное системное соглашение состоит в передаче подпрограмме адреса, куда надо возвращать значение. На этих машинах GNU CC конфигурован для совместимости со стандартным транслятором, когда используется этот метод. Он не может быть совместим для структур 1, 2, 4 или 8 байтов.

GNU CC использует стандартное соглашение системы для передачи параметров. На некоторых машинах первые несколько параметров передаются в регистрах; на других все передаются в стеке. Можно было бы использовать регистры для передачи параметров на любой машине, и это, вероятно, дало бы значительное ускорение. Но результатом была бы полная несовместимость с кодом, построенным по стандартному соглашению. Так что это изменение можно осуществлять, только если Вы используете лишь один GNU CC из трансляторов C для системы. Мы сможем выполнять регистровую передачу параметра на определенных машинах, как только у нас будет такая полная GNU система, что мы сможем компилировать библиотеки при помощи GNU CC.

На некоторых машинах (особенно Sparc), некоторые типы параметров передаются "невидимой ссылкой". Это означает, что значение сохраняется в памяти, и адрес ее расположения в памяти передается подпрограмме.

Если Вы используете " longjmp ", остерегайтесь автоматических переменных. ANSI C говорит,что автоматические переменные, которые не объявлены "volatile", имеют неопределенные значения после " longjmp ". И это - все, что GNU CC обещает делать, потому что очень трудно восстановить регистровые переменные правильно, и одна из особенностей GNU CC - то, он это может помещать переменные в регистры без вашего требования.

Если Вы хотите, чтобы переменная не изменялась после "longjmp", и Вы не хотите писать "volatile", потому что старые C трансляторы не воспринимают это, просто вычислите адрес переменной. Если адрес переменной когда-либо вычислялся, пусть только для того, чтобы вычислить его и игнорировать его, то переменная не может входить в регистр:

      {
        int careful;
        $careful;
        ...
      }

Код, компилируемый GNU CC, может вызывать некоторые библиотечные подпрограммы. Большинство из них обрабатывают арифметику, для которой не имеется никаких команд. Это включает умножение и деление на некоторых машинах, и операции с плавающей точкой на любой машине, на которой поддержка плавающей точки отключена с помощью "-msoft-float". Некоторые стандартные части библиотеки C, типа "bcopy" или "memcpy", также вызываются автоматически. Обычный интерфейс вызова функций используется для вызова библиотечных подпрограмм.
Эти библиотечные подпрограммы должны быть определены в библиотеке "libgcc.a", которую GNU CC автоматически ищет всякий раз, когда линкует программу. На машинах, которые имеют команды умножения и деления при использовании аппаратной поддержки плавающей точки "libgcc.a" обычно не необходим, но ищется на всякий случай.

Каждая арифметическая функция определена в " libgcc1.c " для использования соответствующего арифметического оператора C. Как только файл будет скомпилирован другим транслятором C, который поддерживает все арифметические операторы C, этот файл будет работать машиннонезависимо. Однако, " libgcc1.c " не будет работать, если его скомпилировать GNU CC, потому что каждая арифметическая функция скомпилируется в обращение к себе!