0

I have an assembly program that doesn't work:

  .data
.LC0:
  .string "%f%f"
b:
  .long 1085066445
a:
  .long 1078774989
  .text
  .globl  main
main:
  pxor  %xmm0, %xmm0
  pxor  %xmm1, %xmm1
  movl  $.LC0, %edi
  movl  $2, %eax           # %eax magic
  cvtss2sd  a(%rip), %xmm0
  cvtss2sd  b(%rip), %xmm1
  call  printf
  xorl  %eax, %eax
  ret

The problem is in printf. In fact, when I comment out that line, the program ends normally. Then, I inspected the assembly output of the same program written in C and I saw that the compiler first subtracts 8 to rsp, and then, after printf, it adds 8 again. What is going on? This is the corresponding C program

float a = 3.2, b = 5.4;
int main() { printf("%f%f", a, b); }
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
dVNE
  • 161
  • 9
  • Are you basically calling `printf(%f%f, a, b)`? – Jonny Henly Sep 09 '21 at 17:01
  • 2
    The application binary interface (ABI) of some platforms requires that the stack pointer be aligned to a multiple of 16 bytes at function calls. Called routines, such as `printf`, may assume this requirement is met and use instructions that require 16-byte alignment and that cause a segmentation fault if the stack pointer is misaligned. Are you working on such a platform? – Eric Postpischil Sep 09 '21 at 17:04
  • @JonnyHenly yes – dVNE Sep 09 '21 at 17:05
  • @EricPostpischil. I'm on a x64_86 i7-10510 CPU based on skylake. Running linux – dVNE Sep 09 '21 at 17:06
  • @JonnyHenly. They are float. But that (.long 1085066445 and .long 1078774989) is their true representation. – dVNE Sep 09 '21 at 17:07
  • 1
    [For Linux x86_64 (not x64_86), the stack should be 16-byte aligned in function calls: “The end of the input argument area shall be aligned on a 16 byte boundary. In other words, the value (%rsp − 8) is always a multiple of 16 when control is transferred to the function entry point.”](https://refspecs.linuxbase.org/elf/x86_64-abi-0.21.pdf) – Eric Postpischil Sep 09 '21 at 17:09
  • @EricPostpischil: We have some canonical duplicates for this bug: [Printing floating point numbers from x86-64 seems to require %rbp to be saved](https://stackoverflow.com/q/16097173) being about printf with non-zero AL (which results in some `movaps` stores of the arg-passing XMM regs being executed right away), and one about glibc scanf which in recent years ends up getting compiled to include a 16-byte copy of some struct to or from its stack frame. [glibc scanf Segmentation faults when called from a function that doesn't align RSP](https://stackoverflow.com/q/51070716) – Peter Cordes Sep 10 '21 at 01:13

1 Answers1

2

SSE instructions require the stack to be 16 bytes aligned. That's why this code fails only when printing floating-point numbers and not integers. See https://patchwork.kernel.org/project/linux-crypto/patch/20170110143340.GA3787@gondor.apana.org.au/

dVNE
  • 161
  • 9
  • Very recent builds of glibc printf also break with AL=0, when not printing any floats; we had one such question in the past month or two. Same as for glibc scanf for a few years, see the linked duplicate. Modern GCC finds ways to take advantage of 16-byte copies for local structs sometimes. (Distros typically compile glibc with at least `-O2` enabled, like for most binary packages.) – Peter Cordes Sep 10 '21 at 01:16