Printing a number in x86-64 assembly - linux

Okay, all I am trying to do is print a number (up to 18446744073709551616) in x86-64 assembly for Linux. Can anyone please tell me why this program will not work? All that happens is that it runs and exits. Thank you for all the help you can give!
GLOBAL _start
SECTION .text
;PRINTCHAR
; MOV [LETTER],RAX
;
; MOV RAX,1
; MOV RDI,1
; MOV RSI,LETTER
; MOV RDX,1
; SYSCALL
; RET
PRINTDEC:
MOV R9,18 ;SO IT CAN POINT TO THE END OF THE BUFFER
MOV R10,0
START:
MOV R8,NUMBER
MOV RDX,0 ;CLEAR OUT RDX TO AVOID ERRORS
MOV RBX,10 ;WHAT TO DIVIDE BY
DIV RBX ;DIVIDE OUR NUMBER BY TEN
CMP RAX,0 ;IF OUR QUOTENT IS ZERO THEN WE ARE DONE, PRINT THE BUFFER
JE END
JMP ADDBUF
ADDBUF:
ADD R8,R9 ;MOV TO THE CURRENT LOCATION IN OUR BUFFER
ADD RDX,0x30
; ADD R8,R10
MOV [R8],RDX ;MOV THE LAST NUMBER IN OUR BUFFER TO RDX
DEC R9
INC R10
JMP START
END:
ADD R8,R9 ;add the very last digit
MOV [R8],RDX
INC R10
MOV RAX,1
MOV RDI,1
MOV RSI,R8
MOV RDX,R10
SYSCALL
RET
_start:
MOV RAX,55
CALL PRINTDEC
MOV RAX,60
MOV RDI,0
SYSCALL
SECTION .bss
LETTER: RESB 1
NUMBER: RESB 19

PRINTDEC:
LEA R9, [NUMBER + 18] ; last character of buffer
MOV R10, R9 ; copy the last character address
MOV RBX, 10 ; base10 divisor
DIV_BY_10:
XOR RDX, RDX ; zero rdx for div
DIV RBX ; rax:rdx = rax / rbx
ADD RDX, 0x30 ; convert binary digit to ascii
TEST RAX,RAX ; if rax == 0 exit DIV_BY_10
JZ LAST_REMAINDER
MOV byte [R9], DL ; save remainder
SUB R9, 1 ; decrement the buffer address
JMP DIV_BY_10
LAST_REMAINDER:
TEST DL, DL ; if DL (last remainder) != 0 add it to the buffer
JZ CHECK_BUFFER
MOV byte [R9], DL ; save remainder
SUB R9, 1 ; decrement the buffer address
CHECK_BUFFER:
CMP R9, R10 ; if the buffer has data print it
JNE PRINT_BUFFER
MOV byte [R9], '0' ; place the default zero into the empty buffer
SUB R9, 1
PRINT_BUFFER:
ADD R9, 1 ; address of last digit saved to buffer
SUB R10, R9 ; end address minus start address
ADD R10, 1 ; R10 = length of number
MOV RAX, 1 ; NR_write
MOV RDI, 1 ; stdout
MOV RSI, R9 ; number buffer address
MOV RDX, R10 ; string length
SYSCALL
RET

Related

nasm x86-64, problem with word comparison when exceeding value

I have a counter stocked in a word used for a loop, to end my loop I use :
cmp word [counter], nbIter
jge end
But for some reason it only works for nbIter lesser than 0x8000.
When exceeding this number it jumps to the end at the first iteration.
I tried using two bytes for the counter and comparing the second one whith 0x80 but it was the same result. I still considered the counter as a word when increasing it, I don't know if it was like not doing any change at all.
Here is my full code :
SECTION .data
message: db 13, '0', '0', '.', '0', '0', '0'
msglen: equ $-message
compteur: dw 0
timeval: ; struct needed to call nanosleep system call
dq 0 ; seconds, dq means "define quadwords" = integers on 8 bytes
dq 1000000 ; nanoseconds
SECTION .text
GLOBAL _start
_start:
jmp loop
loop:
call resetreg
mov cx, 10 ; diviseur
mov rbx, 7
mov ax, [compteur]
offset:
dec rbx
cmp rbx, 3
je offset
xor rdx, rdx
div cx ; quotient dans ax, reste dans dx
add dl, '0'
mov [rbx+message], dl
cmp ax, 0
jg offset
; push les registres qu'on risque de modifier
call print
call pause
; pop les registres qu'on a push pour récup leur valeurs
inc word [compteur]
cmp word [compteur], 0x7fff
jge end
jmp loop
end:
call skipline
mov rax, 60 ; system call for exit
mov rdi, 0 ; exit code 0, equiv to xor rdi, rdi
syscall ; invoke operating system to exit
pause:
mov rax, 35 ; syscall nanosleep for x86_64, see man nanosleep
mov rdi, timeval ; pointing to struct encoding duration of sleep
mov rsi, 0 ; null means 2nd parameter not used
syscall
ret
print:
mov rax, 1 ; system call for write
mov rdi, 1 ; file handle 1 is stdout
mov rsi, message ; address of string to output
mov rdx, msglen ; number of bytes
syscall ; invoke operating system to do the write
ret
resetreg:
xor rax, rax
xor rbx, rbx
xor rcx, rcx
xor rdx, rdx
ret
skipline:
mov word [message+1], 0x0a00
mov dword [message+3], 0x00000000
call print
ret
jge is a jump for a signed comparison, you're probably looking for jae for unsigned comparison

How to compare the count of command line arguments correctly in NASM?

I am learning x86_64 NASM assembly on Ubuntu 16.10 on Docker for Mac.
The following program takes two command line arguments, and sum these.
If number of command line arguments is not two, print error message (jump to argcError).
When I exec this program, it jump to argcError section despite passed to two command line arguments.
Why this program jump to argError?
section .data
SYS_WRITE equ 1
STD_IN equ 1
SYS_EXIT equ 60
EXIT_CODE equ 0
NEW_LINE db 0xa
WRONG_ARGC db "Must be two command line arguments", 0xa
section .text
global _start
_start:
pop rcx
cmp rcx, 3
jne argcError
add rsp, 8
pop rsi
call str_to_int
mov r10, rax
pop rsi
call str_to_int
mov r11, rax
add r10, r11
argcError:
mov rax, 1
mov rdi, 1
mov rsi, WRONG_ARGC
mov rdx, 35
syscall
jmp exit
str_to_int:
xor rax, rax
mov rcx, 10
next:
cmp [rsi], byte 0
je return_str
mov bl, [rsi]
sub bl, 48
mul rcx ; rax = rax * rcx
add rax, rbx
inc rsi
jmp next
return_str:
ret
int_to_str:
mov rdx, 0
mov rbx, 10
div rbx
add rdx, 48
add rdx, 0x0
push rdx
inc r12
cmp rax, 0x0
jne int_to_str
jmp print
print:
; calculate byte length of number string
mov rax, 1
mul r12
mov r12, 8
mul r12
mov rdx, rax
; print sum
mov rax, SYS_WRITE
mov rdi, STD_IN
mov rsi, rsp
syscall
jmp printNewline
printNewline:
mov rax, SYS_WRITE
mov rdi, STD_IN
mov rsi, NEW_LINE
mov rdx, 1
syscall
jmp exit
exit:
mov rax, SYS_EXIT
mov rdi, EXIT_CODE
syscall
There probably other errors in your code as pointed out by Micheal Petch, but the way you've initialized RSI is incorrect. Yes, ESP does point to the number of arguments passed, but popping it off the stack and then adding 8 to ESP again is functionally equivalent too.
mov rcx, [rsp]
Then by popping into RSI it only becomes a copy of RCX. If you want to do that it should look like this
pop rcx
.......
add rsp, 24 ; Now RSP is pointing to proper place in array of pointers
pop rsi
add rsp, 16 ; Now point to pointer to second argument
pop rsi
An alternative would be this next example only because my personal preference is not to use stack pointer for other than that which it was intended.
mov rsi, rsp
lodsq ; Read # of arguments passed by OS
add rsi, 8 ; bounce over application name
cmp al, 3
jnz argError
push rsi
lodsq
mov rsi, rax ; RSI points to first agument
call Convert
pop rsi
lodsq
mov rsi, rax
call Convert

Assembly AMD64 gradient error

I'm not sure where I have errored, I'm trying to output a gradient pattern from 0-255 red horizontally and 0-255 green vertically. I know the linked files worked correctly as they have been throughly tested. Any help would be very appreciated.
global _start
global start
extern writeRGB
extern writeHeader
_start:
call start
sys_write: equ 1
sys_open: equ 2
sys_close: equ 3
sys_exit: equ 60
newLine : equ 10
section .data
filename: db "gradient.ppm", 0
section .bss
buffer: resb 4096
section .text
start:
push r12
push r13
push r14
push r15
push rbx
push rbp
mov rax, sys_open ; setup to open file
mov rdi, filename ; move filename
mov rsi, 577 ; given
mov rdx, 0o644 ; given
syscall ; open file
cmp rax, 0 ; check status
jl end
mov r12, 0 ; red
mov r13, 0 ; green
mov r14, rax ; opened file
mov r15, buffer ; buffer
mov rbx, 0 ; buffer counter
lea rdi, [r15+rbx] ; setup for writeheader call
mov rsi, 256
mov rdx, 256
call writeHeader
add rbx, rax ; add buffer space used by writeheader
call makeRGB ; create 0 0 0 rgb
lea rdi, [r15+rbx] ; setup for writeRGB
call writeRGB
add rbx, rax ; add buffer space used by writeRGB
call incRed
incRed:
call addSpace
inc r12 ; red++
call makeRGB ; convert to RBG
lea rdi, [r15+rbx] ; setup for writeRGB call
call writeRGB
add rbx, rax ; add buffer space used by writeRGB
cmp r12, 255 ; check to see if end of row
jl incRed ; if not end of row repeat
je incGreen ; if end of row start new row
incGreen:
cmp r13, 255 ; if last line is written move to end
je write
call addNewLine
mov r12, 0 ; reset red to 0
inc r13 ; green++
call makeRGB ; convert to RGB
lea rdi, [r15+rbx] ; setup for writeRGB call
call writeRGB
add rbx, rax ; add buffer space used by writeRGB
call addSpace
jmp incRed ; ret to incRed
makeRGB:
mov r12, rsi ; mov red into rsi
shl rsi, 8 ; shift left 8 to make room for green
add rsi, r13 ; add green
shl rsi, 8 ; shift left to set blue to 0
ret
addSpace:
mov al, ' ' ; insert space
mov [r15+rbx], al
inc rbx
ret
addNewLine:
mov al, newLine ; insert newline
mov [r15+rbx], al
inc rbx
ret
write:
mov rax, sys_write
mov rdi, r14 ; move opened file into rdi
mov rsi, r15 ; buffer location
mov rdx, rbx ; load buffer size
syscall ; write to file
mov rbp, rax ; status stored in rbp
cmp rbp, 0 ; check status
jl end
mov rdi, r14 ; move opened file into rdi
mov rax, sys_close ; close file
syscall
call end ; end
end:
pop rbp
pop rbx
pop r15
pop r14
pop r13
pop r12
mov rdi, rax ; prepare to exit
mov rax, sys_exit
syscall ; exit

Displaying 64-bit register in ASM

This is my first attempt in 64-bit assembly under Linux. I am using FASM.
I am converting a 64-bit register hex value to string. It is working fine until it reaches the final digit. I can't figure out exactly what's wrong with my code. Maybe there is something about 64-programming that I don't know or with the syscall (I am a linux noob as well)
format ELF64 executable 3
entry start
segment readable executable
start:
mov rax,3c5677h ;final '7' is not displayed
push rax
call REG
;call line
xor edi,edi ;exit
mov eax,60
syscall
;----------------------------------
REG:push rbp ;stack frame setup
mov rbp,rsp
sub rsp,8 ;space for local char
mov rax,[rbp+16];arg
lea r9,[rsp-8] ;local char
mov rcx,16 ;divisor
mov rsi,16 ;16 hex digits for register
.begin: ;get the digit
xor rdx,rdx ;by division
div rcx ;of 16
push rdx ;from back to front
dec rsi
test rsi,rsi
jz .disp
jmp .begin
.disp: ;convert and display digit
inc rsi
pop rax ;In reverse order
add rax,30h ;convert digit to string
cmp rax,39h ;if alpha
jbe .normal
add rax,7 ;add 7
.normal:
mov [r9],rax ;copy the value
push rsi ;save RSI for syscall
mov rsi,r9 ;address of char
mov edx,1 ;size
mov edi,1 ;stdout
mov eax,1 ;sys_write
syscall
pop rsi ;restore RSI for index
cmp rsi,16
je .done
jmp .disp
.done:
add rsp,8 ;stack balancing
pop rbp
ret
Thanks in advance for your help.
I believe the problem printing the last digit comes from how you load r9. If on entry, rsp was 100. You subtract 8 (rsp = 92), then load r9 with rsp - 8 (r9 = 84). Presumably you meant r9 to 100, so try changing that to:
lea r9, [rsp+8]
For a more efficient solution, how about something more like this (assumes value in rbx):
mov r9, 16 ; How many digits to print
mov rsi, rsp ; memory to write digits to
sub rsp, 8 ; protect our stack
mov edx, 1 ; size is always 1
mov edi, 1 ; stdout is always 1
.disp:
rol rbx, 4 ; Get the next nibble
mov cl, bl ; copy it to scratch
and cl, 15 ; mask out extra bits
add cl, 0x30 ; Convert to char
cmp cl, 0x39 ; if alpha
jbe .normal
add cl, 7 ; Adjust for letters
.normal:
mov [rsi], cl ; copy the value
mov eax, 1 ; sys_write
syscall ; overwrites rcx, rax, r11
dec r9 ; Finished a digit
jnz .disp ; Are we done?
add rsp, 8 ; Done with the memory

64bit NASM file handling problems

I managed to write a NASM program on my 64bit Linux system which removes non-letter symbols from an input and prints each word in separate line. The problem is that I get RCX = -1 where i have to get the readed character number , and as a result I get segmentation fault. I've already spent hours trying to figure out how to fix this bug. Hope you guys will be able to help me. Thanks in advance.
Heres my code:
section .data
file1 db "data", 0
file2 db "results", 0
text times 255 db 0
textSize equ $ - text
buff times 255 db 0
buffSize equ $ - buff
section .text
global main
main:
mov rax, 2
mov rdi, file1
mov rsi, 0 ;read only
mov rdx, 0x7777
syscall ;open file1
mov rbx, rax ;save fd to rbx
mov rsi, text ; a pointer to the current character
mov rax, 0
mov rdi, rbx ;fd of file1
mov rsi, text
mov rdx, textSize
syscall ;read the text from file1
mov rax, 3
mov rdi, rbx
syscall ;close file1
mov rcx, rax ; rcx - character counter
mov rbx, buff ;rbx will be our buffer
cmp rcx, 0
je exit ; if nothing to read - exit
process_loop1:
mov dl, byte[rsi]
cmp byte[rsi], 0x41 ; "A"
jl inc1
cmp byte[rsi], 0x5a ; "Z"
jle save
cmp byte[rsi], 0x61 ; "a"
jl inc1
cmp byte[rsi], 0x7a ; "z"
jle save
jmp inc1 ;check text
inc1:
inc rsi
dec rcx
jnz process_loop1
jmp print
save:
mov byte [ebx], dl
jmp inc2 ;save letters
inc2:
inc rsi
inc rbx
dec rcx
jnz process_loop2
jmp print
process_loop2:
mov dl, byte[rsi]
cmp byte[rsi], 0x41 ; "A"
jl enter
cmp byte[rsi], 0x5a ; "Z"
jle save
cmp byte[rsi], 0x61 ; "a"
jl enter
cmp byte[rsi], 0x7a ; "z"
jle save
jmp enter
enter:
mov byte [ebx], 10 ;enter
inc rsi
inc rbx
dec rcx
jnz process_loop1
jmp print
print:
mov rax, 2
mov rdi, file2
mov rsi, 1 ;write only
mov rdx, 0x7777
syscall ;open file2
mov rbx, rax ;save fd to rbx
mov rax, 1
mov rdi, rbx
mov rsi, buff
mov rdx, buffSize
syscall ;print result
mov rax, 3
mov rdi, rbx
syscall ;close file2
jmp exit
exit:
mov rax, 60
mov rdi, 0
syscall
You have a sys_close between the sys_read and the time you try to check the number of bytes received. Thus, you are checking the return value of the close, not the read. Also note that rcx is destroyed by syscall so you can't just move up the mov rcx, rax line.
Also, in a few places you use [ebx] instead of [rbx].
Furthermore, you probably want use O_CREAT for the result file and only write as many bytes as you have processed, not buffSize.
section .data
filename db 'AVG.asm'
section .bss
buffer resb 2000
fd_in resb 1
section .text
global _start
_start:
mov rax,2
mov rdi,filename
mov rsi,0
mov rdx,0777
syscall
mov [fd_in],rax
mov rax,0
mov rdi,[fd_in]
mov rsi,buffer
mov rdx,2000
syscall
mov rax,1
mov rdi,1
mov rsi,buffer
mov rdx,2000
syscall
mov rax,3
mov rdi,[fd_in]
syscall
mov rax,60
mov rdi,0
syscall

Resources