32-битный код не может push
64-битный double
из памяти с одной инструкцией.64-битный код не передает аргументы в стеке, поэтому я предполагаю, что это должен быть 32-битный код.(Также от использования int 0x80
.)
push double
в 32-битном коде равно pushl
, что выдвигает младшие 4 байта .printf
брал старшие 4 байта (содержащие экспоненту и наиболее значимые биты мантиссы) из всего, что было над ним в стеке.В этом случае, предполагая, что scanf
не сгущает свои аргументы стека, старшие 4 байта вашего double
битового шаблона были получены с адреса $format_indouble
.
Возможно, вы хотите pushl double+4
;pushl double
чтобы сдвинуть 8-байтовый double
на две половины.
(Суффикс размера операнда здесь необязателен, но я бы порекомендовал его, чтобы избежать неоднозначности, которая вас захватила.)
Или вы можете использовать SSE2 movsd
для копирования 8 байт в стек.
sub $8, %esp
movsd double, %xmm0
movsd %xmm0, (%esp)
(push
является специальным и может копировать из памяти в память. Инструкции с явным источником иназначение не может этого сделать.)
Конечно, вам не нужно статическое хранилище для ваших входов;Вы можете передавать указатели на стек в scanf
.Тогда ваш double
будет уже в стеке, и вы можете просто сохранить указатель на строку формата под ним.
Кстати, у вас нет стека, выровненного на 16, когда вы вызываетеscanf
и printf
.ABI требует этого, так что вам повезло, что ваша сборка glibc не использует movaps
в памяти стека в этих функциях, что может привести к segfault.
До вызова main
стек выравниваетсяна 16. Это call
выдвигает обратный адрес.Таким образом, еще 3 нажатия повторно выравнивают этот стек.Одно пустое нажатие на запись функции настроит вас на функции с 8 байтами аргументов.
Также обычно вы бы add $8, %esp
после вызова вернулись, чтобы удалить аргументы из стека.
Имена переменных: double
- это имя типа (и ключевое слово) в C. Это делает его странным именем для программы сборки, которая вызывает функции C.Что-то вроде dbl
может выглядеть лучше.