Когда мы помещаем _stdcall
(вызывающему не нужно очищать стек) в прототип функции, заботится ли об этом компилятор или компоновщик?
Является ли соглашение о вызовах компилятором или компоновщиком?
Ответы (3)
Соглашение о вызовах влияет на генерацию кода, поэтому этим занимается компилятор. Линкеру не нужно знать об этом.
extern "C"
, очевидно, соглашение о вызовах не может быть искажено в имени. Если функция extern "C++"
, нет причин, по которым она не может быть.
- person James Kanze; 05.05.2011
Соглашение о вызовах заключается в том, как вызывать функцию (конкретный машинный код для подготовки параметров и очистки ctack), а компоновщик определяет какую функцию (функцию, по какому адресу) вызывать.
Поэтому обычно компилятор генерирует правильный код и оставляет «заполнители» для точных адресов функций, а компоновщик затем помещает туда фактические адреса. При этом существует так называемая генерация кода во время компоновки, где оба делается компоновщиком.
В некоторых системах объектный файл представляет собой просто набор данных, символов и точек исправления. Объектный файл сообщит компоновщику, что этот байт 574 связанного кода должен быть исправлен, чтобы содержать MSB разницы между символами Foo и Bar, и компоновщик сделает это, но компоновщик не имеет представления о значении, выходящем за пределы списка вычисления, которые необходимо выполнить.
В некоторых других системах компоновщик может гораздо больше заниматься генерацией кода. Например, некоторые процессоры ARM могут выполнять код, закодированный с использованием 16-битного или 32-битного набора инструкций. Некоторые типы кода могут эффективно работать только с использованием 32-битного набора инструкций; некоторые будут работать адекватно, но будут более компактными, используя 16-битный набор. Компоновщик ARM знает, какие подпрограммы написаны с использованием каждого набора инструкций, и если код, написанный с использованием одного набора инструкций, попытается вызвать функцию, написанную с использованием другого, компоновщик сгенерирует метод-оболочку, называемый «шпон», и вызовет первый вызов функции, который . Затем шпон выполнит операции, необходимые для вызова другого метода. Несмотря на то, что оболочка представляет собой «код», она полностью создается компоновщиком.
На самом деле нет фиксированного разделения труда между компиляторами и компоновщиками. Я видел некоторые системы, в которых «компилятор» переводит программу в «промежуточную» форму, а компоновщик выполняет всю реальную генерацию кода и проводит оптимизацию в зависимости от того, где что находится в памяти. Как уже отмечалось, есть и другие, в которых компоновщик представляет собой не что иное, как «обработчик исправлений». Вероятно, любое мыслимое разделение труда между этими крайностями существует где-то в какой-то системе.