2013-08-04 2 views
4

Если я скомпилировать пустую функцию CПочему пустая функция не только возврат

void nothing(void) 
{ 
} 

с помощью gcc -O2 -Sclang) на MacOS, он генерирует:

_nothing: 
    pushq %rbp 
    movq %rsp, %rbp 
    popq %rbp 
    ret 

Почему gcc не удалить все, кроме ret? Кажется, это простая оптимизация, если она действительно не делает что-то (кажется, не для меня). Этот шаблон (push/move в начале, pop в конце) также отображается в других непустых функциях, где rbp в противном случае не используется.

В Linux с использованием более поздних gcc (4.4.5) Я вижу только

nothing: 
    rep 
    ret 

Почему в rep? rep отсутствует в непустых функциях.

+0

У меня нет 4.5.5, но я посмотрю на его установку. Но clang дает те же избыточные коды, поэтому я подумал, что может быть причина ... –

+1

_ "Почему' rep'? "_. Причина [поясняется здесь] (http://repzret.org/p/repzret/). – Michael

+0

Что делать, если вы явно указываете '-fomit-frame-pointer' при компиляции на OSX? – Michael

ответ

3

Почему репутация?

Причины объяснены in this blog post. Короче говоря, переход непосредственно к однобайтовой команде ret испортит предсказание ветвления на некоторых процессорах AMD.И вместо добавления nop до ret был добавлен бессмысленный префиксный байт, чтобы сохранить пропускную способность декодирования команд.

Реп отсутствует в непустых функциях.

Цитата из сообщения в блоге я связан с: «[rep ret] предпочтительно простого ret либо когда цель любого вида отрасли, условной (jne/je/...) или безусловной (jmp/call/... ,
В случае пустой функции ret был бы прямой целью call. В непустой функции это не так.

Почему gcc не удаляет все, кроме ret?

Возможно, некоторые компиляторы не будут пропускать код указателя кадра, даже если вы указали -O2. По крайней мере, с помощью gcc вы можете явно указать компилятору опустить их, используя опцию .

-3

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

Они не могут генерировать более качественный код, чем их создатели заставляли их генерировать.

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

Хотя один префикс «rep», вероятно, является ошибкой. Он ничего не делает при использовании без строковой команды, но в любом случае в каком-то более новом процессоре теоретически может вызвать исключение. (и IMHO должен)

+0

Это так приятно и полезно ответить на все, что нравится толпе. – johnfound

1

Я подозреваю, что на раннем этапе ваш последний код является ошибкой. Как сообщает johnfound. Первый код, потому что все компиляторы C всегда должны следовать _cdecl вызовов, что в функции средстве (в Intel, извините, я не знаю, что AT & T синтаксиса):

Функция Определение

_functionA: 
push rbp 
mov rbp, rsp 
;Some function 
pop rbp 
ret 

В вызывающий:

call _functionA 
sub esp, 0 ; Maybe if it zero, some compiler can strip it 

Почему GCC всегда следовать _cdecl вызовов, когда не следует, что это нонсенс, что компилятор не умнее, что передовая сборка программист. Таким образом, он всегда следует за _cdecl любой ценой.

2

Как объяснено здесь: http://support.amd.com/us/Processor_TechDocs/25112.PDF, двухбайтовая ближней возврата инструкции (т.е. rep ret) используются потому, что возврат однобайтного может мне на некоторых изолированных ошибочный на некоторых amd64 процессорах в некоторых ситуациях, такие, как этот.

Если вы играете с процессором, ориентированным на gcc, вы можете обнаружить, что вы можете создать его однобайтное ret. -mtune=nocona работал для меня.

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