Reputation: 49
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
Upvotes: 2
Views: 412
Reputation: 57922
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.
Upvotes: 7