Подтвердить что ты не робот

Различия в инициализации регистра EAX при вызове функции в C и С++

Существует любопытная разница между сборками небольшой программы, когда она скомпилирована как C-программа или как С++-программа (для Linux x86-64).

Код, о котором идет речь:

int fun();
int main(){
    return fun();
}

Компиляция в виде C-программы (с gcc -O2) дает:

main:
    xorl    %eax, %eax
    jmp fun

Но компиляция в виде С++-программы (с g++ -02) дает:

main:
    jmp _Z3funv

Я нахожу загадочным, что C-версия инициализирует возвращаемое значение основной функции с помощью 0 (xorl %eax, %eax).

Какая особенность C-языка отвечает за эту необходимость?

Изменить: Верно, что для int fun(void); инициализация eax-регистра не является.

Если прототипа fun вообще нет, то есть:

int main(){
    return fun();
}

тогда C-компилятор снова повторяет регистр eax.

4b9b3361

Ответ 1

В C int fun(); может принимать любое количество аргументов, поэтому может быть даже функцией varargs. В С++, однако, это означает, что он не принимает никаких аргументов.

В соглашении x86-64 sysv abi требуется, чтобы регистр AL должен содержать число регистров SSE, используемых при вызове функции varargs. Вы, конечно, не передаете никаких аргументов, поэтому он обнуляется. Для удобства компилятор решил обнулить все eax. Объявите свой прототип как int fun(void);, а xor исчезнет.

Ответ 2

По-видимому, это защитная мера, предназначенная для ситуаций, когда функция прототипа fun фактически является вариационной функцией, как объясняется ответом @Jester.

Обратите внимание, что это объяснение не содержит воды с точки зрения стандартного языка C.

С начала стандартизованных времен (C89/90) язык C явно потребовал, чтобы все вариационные функции были объявлены прототипом до точки вызова. Вызов не-прототипированной вариационной функции вызывает поведение undefined в стандартном C. Таким образом, формально компиляторы не должны учитывать возможность fun быть переменным - если это так, поведение будет undefined в любом случае.

Кроме того, как отметил в комментариях @Джон Боллинджер в комментариях, согласно стандарту C, не-прототип декларации int fun() фактически исключает дальнейшие вариативные декларации прототипов fun. То есть вариационная функция не может быть предварительно объявлена ​​как функция (). Это было бы еще одной причиной, по которой указанное выше не-прототипное объявление достаточно для того, чтобы компилятор предположил, что fun не может быть переменным.

Это может быть устаревшая функция, предназначенная для поддержки пред-стандартного кода на C, где предварительная декларация переменных функций с прототипом не требуется.