Различные проблемы с вашим кодом.Самое главное, %f
ожидает double
, но вы передаете float
.См. man 3 printf или книгу C.Кроме того, float
- это 4 байта, поэтому вам рекомендуется распределить 4 байта, а не 1. Чтобы еще хуже, вы даже не используете выделенный 1 байт, поскольку он равен (%esp)
, но вы использовали 1(%esp)
.Для дублирования вам понадобится 8 байтов.Далее вы забыли вытолкнуть значение из FPU.Кроме того, современные соглашения о вызовах требуют 16-байтового выровненного стека даже в 32-битном режиме.
Наконец, не рекомендуется использовать системный вызов exit непосредственно в main
или другом коде, который использует функцию libc.Вместо этого просто ret
или call exit
, если вы действительно настаиваете на том, чтобы очистка libc (например, очистка буферов stdio) происходила.В противном случае вы не получите никакого вывода, если перенаправите стандартный вывод в файл, чтобы он был полностью буферизован.
Вот возможная версия, исправляющая все вышеперечисленное:
.data
float_: .asciz "%f\n"
n1: .float 10.4
n2: .float 10.3
.text
.globl main
main:
sub $12, %esp # 8 bytes for double, + 4 bytes for alignment
flds n1
fsubs n2
fstpl (%esp) # pop double from fpu
movl (%esp), %eax # low 4 bytes
movl 4(%esp), %edx # high 4 bytes
call pfl
addl $12, %esp
ret
## input: EDX:EAX = the bit-pattern for a double
pfl:
push %edx
push %eax
push $float_ # 3x push realigns the stack by 16 again
call printf
add $12, %esp
ret
Отскок вашего double
через целочисленные регистры нет необходимости;если вы ввели call printf
в свою основную функцию, вы могли бы просто использовать fstpl
, чтобы поместить double
в стек прямо над указателем на строку формата.
Или ваша pfl
функция принимает свои входные данные в %st(0)
вместо целочисленных регистров, поскольку вы все равно составляете пользовательское соглашение о вызовах.
(Полагаю, ваш следующий вопросбудет почему он печатает 0.099999
вместо 0.1
:))