Я действительно не понимаю, почему gcc вычитает 12 до esp перед вызовом функции.Управление сборкой стека через% esp
pushl %ebp
movl %esp,%ebp
sub $12,%esp
socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
movl $AF_INET,(%esp)
Я действительно не понимаю, почему gcc вычитает 12 до esp перед вызовом функции.Управление сборкой стека через% esp
pushl %ebp
movl %esp,%ebp
sub $12,%esp
socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
movl $AF_INET,(%esp)
Тока * x86 ABI требует указателя стека быть выровнен по модулю 16 в момент вызова функции. Это типичная причина для необъяснимых корректировок указателя стека.
* Я говорю текущий, потому что GCC фактически в одностороннем порядке изменил ABI и представил это требование где-то в серии 3.x. У меня нет ссылок, но может быть кто-то другой может их предоставить. Это изменение предназначалось для оптимизации использования SIMD-инструкций, но на самом деле это не было необходимо для этой цели, и в конечном итоге нарушило совместимость ABI со старым кодом, когда старый код обращается к новому коду, который предполагает выравнивание. Вся история - большой беспорядок.
Если стек выравнивается по границе 16 байтов во время разговора, то на 32-битном X86 вызов выталкивает 4-байтовый адрес возврата в стек, а стек больше не находится на границе 16 байт. Также только первый параметр для вызываемой функции будет находиться на границе 16 байтов, остальные будут зависеть от размера первого параметра и правил выравнивания для остальных параметров. Я не уверен, в чем дело. – rcgldr
@ rcgldr: Дело в том, что вызывающий может знать выравнивание указателя по указателю стека 16 при входе и тем самым может создавать объекты автоматического хранения, выровненные по 16-байтовым границам, без необходимости выровнять указатель стека. Разумеется, выравнивание самого указателя стека было бы тривиальным, и только налагало бы затраты на функции, которым нужны объекты, выровненные по 16 байтам, и избежал бы нарушения совместимости со старым ABI, поэтому все соглашение совершенно глупо. Но это история ... –
Или вызывающий может просто добавить одну инструкцию к типичной последовательности ввода: | push ebp | mov ebp, esp | и esp, 0fffffff0h | , – rcgldr
Во-первых, вы нажимаете значения базового указателя, который уменьшает значения указателя стека. Поскольку push-операция фактически принимает sp upwars, по существу, декодирует адрес. Тогда кадр стека программы c состоит из кода seg, выше которого есть аргументы функции, над которыми сидит sp. Теперь, когда вы хотите получить доступ к 1-му аргументу, переданному функции, вам нужно добавить 12 байтов с 3-х слов, в конце концов, чтобы получить этот аргумент, нужно вынуть 12 байтов.
http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/Mips/stack.html
Я нашел этот ресурс очень полезный
'sub' - вычитание не сложение;) И это означает, что локальные переменные не имеют никакого отношения к вызову сокета. – Jester
Huh :-) редактирование. Я пытаюсь получить this.esp указывает на стек, вычитая какое-то значение из него, он указывает на более низкий адрес, а затем между ними используется память для переменных? У меня даже смысл? – asla
Да, вот как это работает. – Jester