2014-10-05 4 views
-1

Я действительно не понимаю, почему gcc вычитает 12 до esp перед вызовом функции.Управление сборкой стека через% esp

pushl %ebp 
    movl %esp,%ebp 
    sub $12,%esp 

    socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); 
    movl $AF_INET,(%esp) 
+0

'sub' - вычитание не сложение;) И это означает, что локальные переменные не имеют никакого отношения к вызову сокета. – Jester

+0

Huh :-) редактирование. Я пытаюсь получить this.esp указывает на стек, вычитая какое-то значение из него, он указывает на более низкий адрес, а затем между ними используется память для переменных? У меня даже смысл? – asla

+0

Да, вот как это работает. – Jester

ответ

1

Тока * x86 ABI требует указателя стека быть выровнен по модулю 16 в момент вызова функции. Это типичная причина для необъяснимых корректировок указателя стека.

* Я говорю текущий, потому что GCC фактически в одностороннем порядке изменил ABI и представил это требование где-то в серии 3.x. У меня нет ссылок, но может быть кто-то другой может их предоставить. Это изменение предназначалось для оптимизации использования SIMD-инструкций, но на самом деле это не было необходимо для этой цели, и в конечном итоге нарушило совместимость ABI со старым кодом, когда старый код обращается к новому коду, который предполагает выравнивание. Вся история - большой беспорядок.

+0

Если стек выравнивается по границе 16 байтов во время разговора, то на 32-битном X86 вызов выталкивает 4-байтовый адрес возврата в стек, а стек больше не находится на границе 16 байт. Также только первый параметр для вызываемой функции будет находиться на границе 16 байтов, остальные будут зависеть от размера первого параметра и правил выравнивания для остальных параметров. Я не уверен, в чем дело. – rcgldr

+0

@ rcgldr: Дело в том, что вызывающий может знать выравнивание указателя по указателю стека 16 при входе и тем самым может создавать объекты автоматического хранения, выровненные по 16-байтовым границам, без необходимости выровнять указатель стека. Разумеется, выравнивание самого указателя стека было бы тривиальным, и только налагало бы затраты на функции, которым нужны объекты, выровненные по 16 байтам, и избежал бы нарушения совместимости со старым ABI, поэтому все соглашение совершенно глупо. Но это история ... –

+0

Или вызывающий может просто добавить одну инструкцию к типичной последовательности ввода: | push ebp | mov ebp, esp | и esp, 0fffffff0h | , – rcgldr

0

Во-первых, вы нажимаете значения базового указателя, который уменьшает значения указателя стека. Поскольку push-операция фактически принимает sp upwars, по существу, декодирует адрес. Тогда кадр стека программы c состоит из кода seg, выше которого есть аргументы функции, над которыми сидит sp. Теперь, когда вы хотите получить доступ к 1-му аргументу, переданному функции, вам нужно добавить 12 байтов с 3-х слов, в конце концов, чтобы получить этот аргумент, нужно вынуть 12 байтов.

http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/Mips/stack.html

Я нашел этот ресурс очень полезный

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