assembly - Cómo imprimir un flotador de precisión simple con printf



x86-64 (1)

printf(3) especificador de formato %f printf(3) quiere un double . No hay forma de hacer que printf acepte un float , solo double o long double .

Las promociones de argumento por defecto de C especifican que las llamadas a funciones variadas como foo(char *fmt, ...) promueven el float al double y realizan las promociones enteras habituales de tipos enteros estrechos a int , para los argumentos finales que coinciden con la ... parte de El Prototipo. (Lo mismo se aplica a todos los argumentos para llamar a funciones sin prototipo). N1570 6.5.2.2 Llamadas a funciones, subsecciones 6 y 7 .

Por lo tanto, C no proporciona ninguna forma para que la persona que llama pase un float a printf , por lo que no tiene conversión, y %f significa double . ( %lf también funciona para el double , suponiendo que la implementación lo ignore para las conversiones no enteras / wchar_t . Se requiere aceptar %lf para el double en las implementaciones de wchar_t C99 / C11 y C ++ 11 , por lo que puede usar con seguridad el mismo formato %lf cadena con un double para printf y scanf ).

Tenga en cuenta que scanf es diferente, ya que float * y double * no se ven afectados por esas promociones.

En este caso, cargue con CVTSS2SD .num, %xmm0 .

Si observa la salida del compilador , verá que gcc hace todo lo que hizo y pxor -zero el registro primero para romper la dependencia falsa del valor anterior de %xmm0 . (El mal diseño de cvtss2sd deja sin cambios los 64 bits superiores del destino). gcc erra por el lado de la precaución e inserta instrucciones de ajuste a cero para romper falsas dependencias en muchos casos.

Probablemente esté obteniendo 0 porque los bits superiores de xmm0 son cero . Cuando printf mira los 64 bits bajos de xmm0 como un double (binario IEEE64 en x86) , encuentra el patrón de bits para 123.4f en los 32 bits bajos de la mantisa, y el resto cero. Esto representa un número muy pequeño (denormal), por lo que sale como cero con %f .

Puede probar el equivalente con un float (por ejemplo, en http://www.h-schmidt.net/FloatConverter/IEEE754.html ), configurando algunos bits en la mitad baja para ver lo que obtiene.

Si utilizó %g (notación científica) o %a (representación hexadecimal del patrón de double bit), aparecerían los bits distintos de cero. (A menos que haya habilitado el modo Denormals Are Zero en el MXCSR).

Estoy tratando de imprimir un número de coma flotante en el ensamblado x86_64 pero solo imprime el valor como cero.

Ya hay algunas preguntas sobre esto. Uno parecía resolverse asegurándose de establecer el número de registros vectoriales que está utilizando en% al . Otro mostró que necesita tener una alineación de pila de 16 bytes . Pero, estoy haciendo ambas cosas y todavía no obtengo la salida correcta.

Este es mi programa:

# prints a floating point value
.section .rodata
.fmt: .string "num: %f\n"
.num: .float 123.4

.section .text
.global main
.type   main, @function
main:
  subq $8, %rsp     # 16-byte alignment

  # print my number
  movss .num, %xmm0 # load float value
  movq $.fmt, %rdi  # load format string
  movb $1, %al      # use 1 vector register
  call printf

  # exit
  addq $8, %rsp     # undo alignment
  movq $0, %rax     # return 0
  ret




x86-64