Вызывающий и вызываемый должны договориться о том, что содержат регистры и стек. Это называется соглашение о вызовах , которое является частью более широкой концепции, называемой двоичный интерфейс приложения (ABI) . Вызываемый определяет, как он хочет вызываться (, т. Е. , должны ли аргументы быть в стеке, в регистрах и т. Д.), А компилятор гарантирует, что генерируемый им код соответствует соглашению о вызовах.
Что касается вашего конкретного вопроса, это зависит от ABI. Иногда, если возвращаемое значение больше 4 байтов, но не больше 8 байтов, его можно разделить на EAX и EDX. Но большую часть времени вызывающая функция просто выделяет некоторую память (обычно в стеке) и передает указатель на эту область вызываемой функции.
Обратите внимание, что роль ОС не так важна, как вы думаете. Двоичные файлы с различными соглашениями о вызовах могут сосуществовать в одной и той же системе, и двоичные файлы могут даже использовать различные соглашения о вызовах внутри страны. ABI ОС важен только тогда, когда двоичный файл вызывает свои системные библиотеки.