Segmentation Fault on Printf - Nasm 64Bit Linux

Segmentation fault on printf - NASM 64bit Linux

The problem is with your stack usage.

First, the ABI docs mandate rsp be 16 byte aligned before a call.

Since a call will push an 8 byte return address on the stack, you need to adjust rsp by a multiple of 16 plus 8 to get back to 16-byte alignment. The 16 * n + 8 is including any push instructions or other changes to RSP, not just sub rsp, 24. This is the immediate cause of the segfault, because printf will use aligned SSE instructions which will fault for unaligned addresses.

If you fix that, your stack is still unbalanced, because you keep pushing values but never pop them. It's hard to understand what you want to do with the stack.

The usual way is to allocate space for the locals in the beginning of your function (the prologue) and free this at the end (epilogue). As discussed above, this amount (including any pushes) should be a multiple of 16 plus 8 because RSP on function entry (after the caller's call) is 8 bytes away from a 16-byte boundary.


In most builds of glibc, printf will only care about 16-byte stack alignment when AL != 0. (Because that means there are FP args, so it dumps all the XMM registers to the stack so it can index them for %f conversions.)

It's still a bug if you call it with a misaligned stack even if it happens to work on your system; a future glibc version could include code that depends on 16-byte stack alignment even without FP args. For example, scanf already does crash on misaligned stacks even with AL=0 on most GNU/Linux distros.

Segmentation fault when using printf in nasm 64bit

Ok, i got it.
It turns out i need to add after main :

push rbp
mov rbp, rsp

So the code looks like this:

section .data
_DATA1 db "aa", 0

section .text
global main
extern printf
main:
push rbp
mov rbp, rsp
sub rsp, 16
lea r13, [_DATA1]
mov rdi, r13
call printf
add rsp, 16
mov rax, 0
mov rsp, rbp
pop rbp
ret

I realise that this is also what gcc do

NASM printf print 64 bit double segfaults

On x86_64, arguments are passed in registers, and not on the stack (the stack is used only if the size of the arguments to too large to fit in the registers). All the gory details1 are laid out in the SYSV ABI for x86_64

The basics of that is that the first 6 integer/pointer arguments are passed in RDI/RSI/RDX/RCX/R8/R9, while the first 8 float/double arguments are passed in XMM0..XMM7. In addition, you need to specify the number of XMM registers used for arguments in AL2. So in your case, you want the format in RDI, the double value in XMM0 and 1 in AL

The wikipedia page also has lots of good (concise) info about this.


1For non-Microsoft systems -- MS being MS they do things in their own incompatible way

2You only actually need to set this for varargs functions that use at least one XMM register. For non-varargs functions it will be ignored, and if it is set too large for a varargs function, the result will be a few wasted cycles (saving uneeded XMM regs), but wont actually break anything.

Segmentation fault ASM on linux at printf

using gcc to link is the easiest way to go if you are going to use functions from the C Library, since gcc takes care of a few things for you "behind the scenes".

To use just ld, you need to link against ld-linux-x86-64.so.2 and pass it -lc to link to the C Library.

Next, you are using printf wrong. If you are not using floating point registers (which you are not) you need to "zero out" rax.

Also, since you are linking against the C Library, you cannot just ret from the main but call exit.

lea     rdi, [fmt]
mov rsi, [rsp+a]
mov rdx, [rsp+b]
mov rcx, [rsp+max]
xor rax, rax ; # of floating point registers used.
call printf

and:

;   print_max ( 100, 200 );
mov rdi, 100 ;first parameter
mov rsi, 200 ;second parameter
call print_max
xor eax, eax ;to return 0
leave

xor rdi, rdi
call exit

ld -o $(APP) $(APP).o -lc -I/lib64/ld-linux-x86-64.so.2

and the output:

max(100,200) = 200

printf gives segmentation fault?

I GOT IT!!!!

I DID IT I FINALLY SOLVED IT!!!

anyway here is the thing i used:

Instead of pushing the format as push fmt,

I instead read the nasm docs, saw some examples and found out that we have to store the format fmt in rdi and the variables in their respective order in rsi, rdx,rcx,r8 and so on.

so I did exactly that and BOOM! pops the answer on execution. MY JOY HAS NO LITERAL BOUNDS

repaired code:

        extern printf

SECTION .data


fmt: db "nCr = %d", 10, 0 ;format for printf (used once)

n: dq 10 ; 64 bit double var n = 10.000
r: dq 2 ; 64 bit int var r = 3
i: dq 0 ; 64 bit int var i = 0
npr: dq 1 ; 64 bit double var npr = 1.000
rfac: dq 1 ; 64 bit int var npr = 1


SECTION .text ; code section
global main

main:
push rbp ; base pointer
mov rax,[npr] ; load npr
mov rbx,[i] ; load i
mov rcx,[n] ; load n
mov rdx,[r] ; load r for condition checking
;sub rdx,[r] ; subtract n - r
;sub rdx,1 ; subtract (n = n-r) - 1. now we can compare it to rdx

jmp loop1 ; Jump to condition first
cloop1 imul rax,rcx ; multiply the word npr with n
dec rcx ; decrement n
inc rbx ; increment i
loop1 cmp rbx,rdx ; Check the condition
jl cloop1 ; Jump to content of the loop if met

mov rdx,[r] ; load r
mov rcx,[rfac] ; load rfac
mov rbx,0 ; set rbx to 0
jmp loop2 ; Jump to condition first
cloop2 imul rcx,rdx ; multiply the word rfac with r
dec rdx ; decrement r
loop2 cmp rbx,rdx ; Check the condition(0<=r)
jl cloop2 ; Jump to content of the loop if met
diva:
mov rdx,0
mov rax,rax
idiv rcx ; divide rax(npr) by rcx(rfac)
mov rdi,fmt ; storing format
mov rsi,rax ; 1st printf var
mov rax,0 ; make it 0?
call printf ; call the function

pop rbp ; pop the stack
mov rax,0 ; exit code
ret ; return to OS from main


Related Topics



Leave a reply



Submit