NASM Forum > Programming with NASM
Segmentation fault question
azagaros:
This is on linux 64. I am getting a segmentation fault at trying to read the command line arguments and print them out. I am not sure where my logic error is or which boundary I am crossing. As far as I know my management of the stack is working.
--- Code: ---section .data
strNewLine db 10
section .text
global _start
_start:
pop rcx ; pop the count of arguments
.argloop:
pop rax ; pop the ptr of the arg.
call _printstr ; print the string
call _printnl ; print a new line character
dec rcx
cmp rcx, 0
jne .argloop
call _ExitProg
ret
;rax ptr to string to count
;rbx count of string
_printstr:
push rcx
push rax
mov rbx,0
.lenloop:
inc rax
inc rbx
mov cl, [rax]
cmp cl, 0
jne .lenloop
mov rax, 1
mov rdi, 1
pop rsi ;pop rax to rsi
mov rdx, rbx
syscall
pop rcx
ret
_printnl:
mov rax, 1
mov rdi, 1
mov rsi, strNewLine
mov rdx, 1
syscall
ret
_ExitProg:
xor rdi, rdi
mov rax, 60
syscall
--- End code ---
Frank Kotler:
I am not good on 64-bit code. It looks like rcx is being trashed in one of your routines. Either save rcx across the two routines, or test rax for zero instead of counting on argc.
I think that'll work...
Best,
Frank
fredericopissarra:
Maybe this could help:
--- Code: ---; test.asm
;
; compile with:
; $ nasm -felf64 -o test.o test.asm
; $ ld -o test test.o
;
bits 64
default rel ; x86-64 default addressing is RIP relative!
; Moved to .rodata.
section .rodata
strNewLine: db `\n`
section .text
global _start
_start:
; argc is in [rsp]
; argv[n] are in [rsp+8*n+8]
;mov ecx,[rsp] ; argc (not used here!)
xor ebx,ebx ; RBX is saved by syscalls (SysV ABI).
; Used as index...
.loop:
mov rdi,[rsp+rbx*8+8]
test rdi,rdi ; argv[rbx] == NULL?
jz .no_more_args
call printstr ; print the string
call printnl ; print a new line character
add ebx,1 ; avoid using INC/DEC (they are slow!).
jmp .loop
.no_more_args:
mov eax,60 ; syscall_exit
xor edi,edi ; exit(0).
syscall
; rdi = string ptr.
strlen:
xor eax,eax
.loop:
cmp byte [rdi+rax],0
jz .strlen_end
add eax,1
jmp .loop
.strlen_end:
ret
;rdi = string ptr
printstr:
call strlen
mov edx,eax ; string length.
mov eax,1 ; syscall_write
mov rsi,rdi ; string ptr.
mov edi,eax ; stdout
syscall
ret
printnl:
mov eax,1 ; syscall_write
mov edi,eax ; stdout
mov edx,eax ; 1 char do print
lea rsi,[strNewLine] ; points to '\n'.
syscall
ret
--- End code ---
azagaros:
Thank you Fredericopissarra. You got me by one stumbling block. Just trying to understand how the registers and stack on linux are handled is being challenging. A small expansion of code has created a new segmentation fault.
--- Code: --- bits 64
default rel ; x86-64 default addressing is RIP Relative
; section .data
section .rodata
strNewLine db 10
strSpace db 32
strFileName db 'is a file name.',0
strOption db 'is an option flag.',0
section .text
global _start
_start:
xor rbx, rbx ;zero the rbx- will not get trashed by sys v abi (the system calls)
; rsp is the **argv
.argloop:
mov rdi, [rsp+rbx*8+8]
test rdi, rdi ; testing for null
jz .noMoreArg ; jump on zero
cmp rbx, 0 ; consuming the first arg.
je .skipProcess
call printstr ; print the string
call printSpc ; print a space
; procecc the arg
call processArg
call printnl ; print a new line character
.skipProcess:
add rbx, 1 ; increment the index.
jmp .argloop
.noMoreArg:
call ExitProg
ret
; rdi = string ptr
strlen:
xor rax, rax ; zero rax register
.loop:
cmp byte[rdi+rax],0 ;check for null termination of string
jz .strlenend
add rax,1
jmp .loop
.strlenend:
ret
; rdi = str ptr
printstr:
call strlen
mov rdx, rax ; store the length rdx
mov rax, 1 ; syscall write
mov rsi, rdi ; str ptr
mov rdi, rax ; stdout
syscall
ret
; rdi = str ptr
printnl:
mov rax, 1
mov rdi, rax
mov rdx, rax
lea rsi, [strNewLine]
syscall
ret
;rdi = str ptr
printSpc:
mov rax, 1
mov rdi, rax
mov rdx, rax
lea rsi, [strSpace]
syscall
ret
; rdi = str ptr to process
processArg:
xor rax, rax ;string index position
cmp byte[rdi+rax],'-'
je .argOption
; is the stack getting trashed? stack alignment? (system calls use the local stack?)
push rdi ; save the current rdi (should not change)
push rax ; save the working rax (It is getting trashed?) (it gets trashed in the string length function)
mov rdi, strFileName ; set up a differnet rdi...
call printstr
pop rax
pop rdi
;Assumed file concept (can have more than one)
;allocate a file infromation block
;copy the file name to the file name of the block
.argOption:
add rax, 1 ;consume the option flag
; the test for the list of options.
push rax
push rdi
mov rdi, strOption
call printstr
pop rdi
pop rax
ret
ExitProg:
xor rdi, rdi
mov rax, 60
syscall
--- End code ---
As for you Kolter as a NASM developer some food for thought:
https://eli.thegreenplace.net/2012/01/03/understanding-the-x64-code-models
every thing I am fighting seems to be in the code generation of Nasm or Fasm for that matter
fredericopissarra:
SysV ABI amd64 calling convention:
The integer arguments (or pointers) are passed to a function in order: RDI, RSI, RDX, RCX, R8 and R9, from 7th argument to the last, they are stored on stack cdecl style. For syscalls, instead of RCX, R10 is used.
For floating point, XMM0 to XMM7 will be used for arguments.
Example: int f( int a, float b, int c ); // EDI=a, XMM0=b, ESI=c
Registers RSP, RBP, RBX and R12 to R15 must be preserved between calls. Any other registers can be changed inside a function.
RAX is the returned value...
Navigation
[0] Message Index
[#] Next page
Go to full version