the following code tries to read the command line arguments and then scans them with sscanf() and use the result to emit utf8 text.
I'm failing to call sscanf() and getting segfault error at the line where I call this function
I have already debugged this and I know where is the problem but not how to solve it.
global main
extern puts
extern sscanf
extern printf
extern emit_utf_8
section .text
main:
cmp rdi, 2
jl argumentsError
add rsi, 8 ; skip the name of the program
forloop:
mov r12, rsi
push rdi
push rsi
push r12
sub rsp, 8 ; must align stack before call
; start of for bloc
xor rax, rax
mov rdi, qword [r12]
mov rsi, codePointFormat
mov rdx, qword [codePoint]
call sscanf
cmp rax, 1
je ifthen
jmp else
ifthen:
mov rdi, codePoint
call emit_utf_8
jmp endif
else:
mov rdi, incorrectFormat
mov rsi, r12
call printf
endif:
; end of for bloc
add rsp, 8 ; restore %rsp to pre-aligned value
pop r12
pop rsi
pop rdi
add rsi, 8 ; point to next argument
dec rdi ; count down
jnz forloop ; if not done counting keep going
ret
argumentsError: mov rdi, argumentsRequiredMessage
call puts
mov rdi, argumentDescription
call puts
xor rax, rax
inc rax
ret
section .data
argumentsRequiredMessage:
db "This program requires one or more command line arguments,", 0
argumentDescription: db "one for each code point to encode as UTF-8.", 0
incorrectFormat: db "(%s incorrect format)", 0
codePointFormat: db "U+%6X", 0
section .bss
codePoint: resb 8 ; The code point from sscanf should go here.
Is there a way to pass that third argument?
sscanf() signature.
in __cdecl sscanf(const char *const _buffer, const char *const _Format, ...)
I'm using ubuntu 19.04 64 bit
Related
I'm trying to convert a c code Fibonacci sequence loop into assembly. But I'm having trouble actually printing the values properly
_start:
push rbp
mov rbp,rsp
sub rsp, 8
mov rdi, asknum
push rdi
xor rax, rax
call printf
mov rdi, format
pop rdi
push rdi
mov rsi, var1
push rsi
xor rax, rax
call scanf
mov rdi, title ; Title = "Fib Numbers"
pop rdi
push rdi ; Title on stack, gets printed with call printf
xor rax,rax
call printf
mov rcx, 10 ; Counter
mov rax, rsi ; Data accumulator; does the calculation for the algebra
mov rbx, 1 ; Temporary value
This is my initialization. I have declared a few variables
section .data
format: db "%d", 0xa, 0
title: db "Fib Numbers", 10, 0
asknum: db "Enter a number to get the fibonacci sequence of: ", 10, 0
section .bss
var1 resd 1 ; Variable for scanf
This is the sort of output I get
Enter a number to get the fibonacci sequence of:
1
4206708
1
4206709
4206710
8413419
12620129
21033548
33653677
54687225
88340902
What do I do to fix that?
section .data
text db 'Put a number',10,0
scanform db '%d'
number dw 0
section .text
extern printf,scanf
global main
main:
push rbp
mov rbp,rsp
push rdi
push rsi
push rbx
mov rdi,text
mov rax,0
call printf
mov rsi,number
mov rdi,scanform
mov rax,0
call scanf
pop rbx
pop rsi
pop rdi
ret
This is my code I write a other codes all day and I do not have problem with these but now when I call scanf, write program received signal SIGSEV, segfault... Specified first and last line in different files. I do not understand this message can someone help me?
You have the following issues:
You forgot to pop rbp.
You misalign the stack which needs to be 16 byte aligned.
You do not zero terminate your format string (thanks to Paul for pointing this out).
You use %d which writes a 4 byte integer but you only allocated 2 bytes with dw.
It is recommended to align integers to 4 bytes.
A possible fixed version:
section .data
number dd 0
text db 'Put a number',10,0
scanform db '%d', 0
section .text
extern printf,scanf
global main
main:
push rbp
mov rbp,rsp
push rdi
push rsi
push rbx
push rbx ; for alignment
mov rdi,text
mov rax,0
call printf
mov rsi,number
mov rdi,scanform
mov rax,0
call scanf
pop rbx
pop rbx
pop rsi
pop rdi
pop rbp
ret
Since rsi and rdi are caller-saved registers and rbx is not touched, you can simplify the code. I also changed to xor zeroing and rip-relative addressing as follows:
section .data
number dd 0
text db 'Put a number',10,0
scanform db '%d', 0
section .text
extern printf,scanf
global main
main:
push rbp
lea rdi, [rel text]
xor eax, eax
call printf
lea rsi, [rel number]
lea rdi, [rel scanform]
xor eax, eax
call scanf
pop rbp
ret
I'm stuck at figuring out to copy the string source to target, which should be initialized to all zeroes. It appears as though I need to find the size of the string, start a counter register, and push stringitem[counter] to the stack, increment counter register. I can't figure out how to even get started, let alone search for a word in the string.
Thanks!
bits 64
global main
extern printf
section .text
main:
; function setup
push rbp
mov rbp, rsp
sub rsp, 32
;
lea rdi, [rel message]
mov al, 0
call printf
;
lea rdi, [rel source]
mov al, 0
call printf
;
;mov edi, source
;mov esi, target
;lea rdi, [esi]
;mov al, 0
;call printf
;mov ecx,sizeof source -1
; mov esi,0
;L1:
; mov eax,source[esi];
; push eax
; inc esi
; loop L1
; function return
mov eax, 0
add rsp, 32
pop rbp
ret
section .data
message: db 'Project',0x0D,0x0a,'Author',0x0D,0x0a,0
source: db 0x0D,0x0a,"I can't figure out how to copy this text to target.",0x0D,0x0a,0
target: db '0000000000000000000000000000000000000000000',0x0D,0x0a,0
For your data memory layout this will do
lea rdi, [rel target]
lea rsi, [rel source]
mov rcx, target-source
cld
rep movsb
Otherwise as Jester said, a simple byte-to-byte copy will also do
lea rdi, [rel target]
lea rsi, [rel source]
cld
.copy:
lodsb
stosb
test al, al
jnz .copy
I am recoding puts using nasm (64bit), and when puts receives NULL as argument it prints (null). I'm trying to recreate that behaviour, except I can't get the code to jump to the part where it prints (null). Instead it just prints nothing
here's my code:
global _my_puts
section .text
%define WRITE 0x2000004
%define STDOUT 1
_my_puts:
cmp rdi, 0
je is_null
mov r8, rdi
cmp byte [r8], 0
jne print_and_add
print_and_add:
mov rax, WRITE
mov rdi, STDOUT
mov rsi, r8
mov rdx, 1
syscall
inc r8
cmp byte [r8], 0
jne print_and_add
mov rax, WRITE
mov rdi, STDOUT
mov rdx, newline.len
lea rsi, [rel newline]
syscall
mov rax, 1
ret
is_null:
mov rax, WRITE
mov rdi, STDOUT
lea rsi, [rel nullmsg]
mov rdx, nullmsg.len
syscall
mov rax, 1
ret
section .data
nullmsg: db "(null)", 10
.len: equ $ - nullmsg
newline: db 10
.len: equ $ - newline
I also tried
test rdi, rdi
je is_null
with no change. Any ideas?
thanks for the help :)
Your first instruction is the problem: cmp rdi, 0. You're comparing the string pointer, passed to my_puts, to the value 0 to determine if you should print "(null)" rather than comparing the first byte of the string to 0. I'm supposing if you pass a 0 pointer, that would be an error.
Try:
_my_puts:
mov r8, rdi
cmp [r8], 0
je is_null
print_and_add:
...
If you want the defensive check against a 0 pointer, you could include that as well, but you wouldn't be checking against any other bad pointers:
_my_puts:
cmp rdi, 0
je bad_pointer
mov r8, rdi
cmp [r8], 0
je is_null
print_and_add:
...
Pretty simple problem.
This nasm is supposed to write a user-written message (i.e. hello) to a file, again determined by user input from an argument. It does this just fine, but the problem is, it writes all the null bytes not used afterwards as well. For example, if I reserve 32 bytes for user input, and the user only uses four for his input, those for bytes will be printed, along with 28 null bytes.
How do I stop printing null bytes?
Code used:
global _start
section .text
_start:
mov rax, 0 ; get input to write to file
mov rdi, 0
mov rsi, msg
mov rdx, 32
syscall
mov rax, 2 ; open the file at the third part of the stack
pop rdi
pop rdi
pop rdi
mov rsi, 1
syscall
mov rdi, rax
mov rax, 1 ; write message to file
mov rsi, msg
mov rdx, 32
syscall
mov rax, 3 ; close file
syscall
mov rax, 1 ; print success message
mov rdi, 1
mov rsi, output
mov rdx, outputL
syscall
mov rax, 60 ; exit
mov rdi, 0
syscall
section .bss
msg: resb 32
section .data
output: db 'Success!', 0x0A
outputL: equ $-output
Well, after doing some digging in header files and experimenting, I figured it out on my own.
Basically, the way it works is that you have to put the user's string through a byte counting process that counts along the string until it finds a null byte, and then stores that number of non-null bytes.
I'll post the workaround I'm using for anyone who's had the same problem as me. Keep in mind that this solution is for 64-bit nasm, NOT 32!
For 32-bit coders, change:
all instances of "rax" with "eax"
all instances of "rdi" with "ebx"
all instances of "rsi" with "ecx"
all instances of "rdx" with "edx"
all instances of "syscall" with "int 80h" (or equivelant)
all instances of "r8" with "edx" (you'll have to juggle this and rdx)
Here's the solution I use, in full:
global _start
; stack: (argc) ./a.out input filename
section .text
_start:
getInput:
mov rax, 0 ; syscall for reading user input
mov rdi, 0
mov rsi, msg ; store user input in the "msg" variable
mov rdx, 32 ; max input size = 32 bytes
xor r8, r8 ; set r8 to zero for counting purposes (this is for later)
getInputLength:
cmp byte [msg + r8], 0 ; compare ((a byte of user input) + 0) to 0
jz open ; if the difference is zero, we've found the end of the string
; so we move on. The length of the string is stored in r9.
inc r8 ; if not, onto the next byte...
jmp getInputLength ; so we jump back up four lines and repeat!
open:
mov rax, 2 ; syscall for opening files
pop rdi
pop rdi
pop rdi ; get the file to open from the stack (third argument)
mov rsi, 1 ; open in write mode
syscall
; the open syscall above has made us a full file descriptor in rax
mov rdi, rax ; so we move it into rdi for later
write:
mov rax, 1 ; syscall for writing to files
; rdi already holds our file descriptor
mov rsi, msg ; set the message we're writing to the msg variable
mov rdx, r8 ; set write length to the string length we measured earlier
syscall
close:
mov rax, 3 ; syscall for closing files
; our file descriptor is still in fd
syscall
exit:
mov rax, 60 ; syscall number for program exit
mov rdi, 0 ; return 0
Keep in mind that this is not a complete program. It totally lacks error handling, offers no user instruction, etc. It is only an illustration of method.