i386 System V ABI дает гарантию / требует выравнивания стека 16 байт перед call
, как я сказал в начале моего ответа, который вы связали.(Если только вы не вызываете частную вспомогательную функцию, в этом случае вы можете создать свои собственные правила для выравнивания, передачи аргументов и того, какие регистры перекрываются для этой функции.)
Функции допускается сбой или неправильное поведение, если вы нарушаете это требование ABI, но не обязаны это делать. например, scanf
в x86-64 Ubuntu glibc (составленный недавним gcc) только недавно начал делать это: scanf Ошибки сегментации при вызове из функции, которая не изменяет RSP
Функции могут зависеть от выравнивания стека для производительности (для выравнивания double
или массива double
s, чтобы избежать кеширования-линии разделяется при обращении к ним).
Обычно единственный случай, когда функция зависит от выравнивания стека для правильности , это когда она скомпилирована для использования SSE / SSE2, поэтому она может использовать 16-байтовое выравниваниетребуется загрузить / сохранить для копирования структуры или массива (movaps
или movdqa
) или для автоматической векторизации цикла над локальным массивом.
Я думаю, что Ubuntu не компилируетсяих 32-битные библиотеки с SSE (за исключением функций типа memcpy
, которые используют диспетчеризацию во время выполнения), поэтому они все еще могут работать на древних процессорах, таких как Pentium II.Многоархатные библиотеки в системе x86-64 должны принимать SSE2, но с 4-байтовыми указателями менее вероятно, что 32-битные функции будут иметь 16-байтовые структуры для копирования.
В любом случае, независимо от причины, очевидно, printf
в вашей 32-битной сборке glibc на самом деле не зависит от правильности выравнивания стека 16 байт, поэтому он не ошибается даже при неправильном выравнивании стека.
Почему 0x2014толкнул вместо 0х14?Что такое 0x201d?
0x14
(десятичное число 20) - это значение в памяти в этом месте.Он будет загружен во время выполнения, потому что вы использовали push r/m32
, а не push $20
(или постоянную времени сборки, такую как .equ testint, 20
или testint = 20
).
Для создания gcc -m32
PIE (Position Independent Executable), который перемещается во время выполнения , потому что это значение по умолчанию в gcc Ubuntu.
0x2014
- это смещение относительно начала файла.Если вы разберетесь во время выполнения после запуска программы, вы увидите реальный адрес.
То же самое для call 54b
.Предположительно, это вызов PLT (который находится рядом с началом сегмента файла / текста, следовательно, с низким адресом).
Если вы разберетесь с objdump -drwC
, вы увидите информацию о перемещении символов.(Мне также нравится -Mintel
, но будьте осторожны, это MASM-подобный, а не NASM).
Вы можете связать с gcc -m32 -no-pie
, чтобы сделать классические исполняемые файлы зависимыми .Я бы определенно рекомендовал это, особенно для 32-битного кода, и особенно, если вы компилируете C, используйте gcc -m32 -no-pie -fno-pie
, чтобы получить не-PIE code-gen, а также ссылки на исполняемый файл без PIE.(см. 32-разрядные абсолютные адреса, более не разрешенные в Linux x86-64? для получения дополнительной информации о PIE.)