clang - бесполезный push rax и pop rcx?

Сегодня, разбирая некоторые бинарники, которые я собрал ранее (clang x86_64), я наткнулся на кое-что [на первый взгляд] бесполезное.

_baz:                                   ## @baz
    .cfi_startproc
## BB#0:
    pushq   %rax ; What?
Ltmp7:
    .cfi_def_cfa_offset 16
    leaq    (%rsp), %rax
    movq    %rsi, (%rax)
    xorl    %edx, %edx
    movq    %rax, %rsi
    callq   _something
    movq    %rax, %rdi
    callq   _something_else
    movl    (%rax), %eax
    popq    %rcx ; What?
    retq
    .cfi_endproc

Я вижу, что rax сохраняется, а затем восстанавливается в rcx, и я не вижу смысла делать это, так как rax — это рабочий регистр (который, кажется, не нуждается в сохранении здесь), а rcx (еще один рабочий регистр, также для 4-й аргумент, переданный регистром), кажется, здесь никогда не используется.


person Mona the Monad    schedule 19.08.2017    source источник
comment
Это самый короткий способ исправить требуемое 16-выравнивание RSP.   -  person harold    schedule 19.08.2017
comment
Звучит понятно, но почему rax и rcx? Почему бы не нажать и поп просто rax?   -  person Mona the Monad    schedule 19.08.2017
comment
Он помещает что-то в eax, предположительно, чтобы вернуть его, поэтому залезть туда было бы плохо. Хотя он мог бы использовать rcx оба раза   -  person harold    schedule 19.08.2017
comment
Какие регистры должны быть сохранены и восстановлены в соответствии с Соглашением о вызовах C — правила вызывающего абонента?   -  person David C. Rankin    schedule 19.08.2017
comment
@harold О, я забыл об этом. Тем не менее, почему все функции не могут просто заменить/добавить rsp на число, кратное 16? В этом случае эта функция не нуждалась бы в дополнительных 8 байтах push/pop, если бы вызывающая сторона предварительно выровняла стек.   -  person Mona the Monad    schedule 19.08.2017
comment
Опять же, есть этот обратный адрес...   -  person Mona the Monad    schedule 19.08.2017
comment
Кроме того, как он узнает, когда и в какой функции выполнять причуду выравнивания стека?   -  person Mona the Monad    schedule 19.08.2017
comment
Каждый нелист должен выравнивать rsp перед вызовом другой функции. Push — это эффективный способ сделать это, если локальные пользователи не нужны.   -  person Jester    schedule 20.08.2017
comment
Он не знает, вот почему он рухнет, если вы забьете его пользовательской функцией в сборке без выравнивания. Он просто ожидает, что rsp был выровнен перед вызовом, т. е. он смещен на +-8 в начале из-за обратного адреса и нуждается в исправлении, если будут выполняться дальнейшие вызовы.   -  person Ped7g    schedule 20.08.2017
comment
Использование push кажется лучше, чем арифметика RSP на процессорах Intel, которые имеют специальную аппаратную поддержку для оптимизации использования стека. stackoverflow.com/a/37774474/597607   -  person Bo Persson    schedule 20.08.2017
comment
К вашему сведению, # — это символ комментария в синтаксисе x86 GAS (даже в режиме -masm=intel). ; работает так же, как и в C, разделяя инструкции/директивы, даже если они находятся в одной строке.   -  person Peter Cordes    schedule 21.08.2017
comment
расширил мои комментарии о возможных недостатках/улучшениях производительности в ответ на дубликат: stackoverflow.com/a/45823778/224132.   -  person Peter Cordes    schedule 22.08.2017