2

I tried to follow a very simple example provided by https://cs.lmu.edu/~ray/notes/nasmtutorial/. I intentionally commented below line to ensure that stack is not aligned to 16 bytes boundary as required by x64 calling convention. But still program continues to work. Please can someone answer why calling convention not being honoured, i was expecting some sort of segmentation fault.

;       sub     rsp, 8                  ; must align stack before call

In order to run this program: (Ubuntu 20.04 lts, gcc 9.3.0)

nasm -felf64 echo.asm && gcc echo.o && ./a.out 123ABC
; -----------------------------------------------------------------------------
; A 64-bit program that displays its command line arguments, one per line.
;
; On entry, rdi will contain argc and rsi will contain argv.
; -----------------------------------------------------------------------------

        global  main
        extern  puts
        section .text
main:
        push    rdi                     ; save registers that puts uses
        push    rsi
;       sub     rsp, 8                  ; must align stack before call

        mov     rdi, [rsi]              ; the argument string to display
        call    puts WRT ..plt          ; print it

;       add     rsp, 8                  ; restore %rsp to pre-aligned value
        pop     rsi                     ; restore registers puts used
        pop     rdi

        add     rsi, 8                  ; point to next argument
        dec     rdi                     ; count down
        jnz     main                    ; if not done counting keep going

        ret

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
  • 1
    If the functions you call like the C library (puts etc) were compiled/assembled using instructions that don't require alignment (like some SSE/AVX instructions) then they may work as expected. Often you'll see alignment problems more if you begin to use floating point operations (like floating point with `printf`). You'd probably find that on MacOS it fails as they seem to use aligned instructions a fair amount in their C library even for integer class data. If you don't align the stack it may or may not work. – Michael Petch Aug 16 '20 at 19:05
  • 9
    Your question is analogous to asking: "I drove my car through a red light and I made it safely to the other side. I was expecting someone to crash into me. Why are the rules of the road not being honored?" – Nate Eldredge Aug 16 '20 at 19:08

1 Answers1

7

Just luck.

One of the main reasons for requiring stack alignment is so that functions can safely use SSE aligned data instructions such as movaps, which fault if used with unaligned data. However, if puts happens to not use any such instructions, or to do anything else which genuinely requires stack alignment, then no fault will occur (though there may still be a performance penalty).

The compiler is entitled to assume that the stack is aligned and that it can use those instructions if it feels like it. So at any time, if your libc is upgraded or recompiled, it may happen that the new version of puts uses such instructions and your code will mysteriously begin failing.

Obviously you don't want that, so align the darn stack like you're supposed to.

There are relatively few situations in C or assembly programming where violating rules like this is guaranteed to segfault or fail in any other predictable way; instead people say things like "the behavior is undefined" meaning that it could fail in any way you can imagine, or then again it might not. So you really can't draw any conclusions from an experiment where illegal code happens to appear to work. Trial and error is not a good way to learn assembly programming.

Nate Eldredge
  • 48,811
  • 6
  • 54
  • 82
  • 1
    TL:DR: "undefined" doesn't mean "required to fail". I like your red-light analogy, that's good. Anyway, this kind of breaks-in-the-future thing has happened in real life: glibc `scanf` now uses a `movaps` to the stack even when properly called with AL=0. [glibc scanf Segmentation faults when called from a function that doesn't align RSP](https://stackoverflow.com/q/51070716) Older builds of x86-64 glibc didn't do that, and it also doesn't happen in 32-bit code, despite the i386 System V ABI having the same 16-byte stack alignment guarantee/requirement. – Peter Cordes Aug 16 '20 at 19:22