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

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

Related

Nasm: Print on console

I made this program that open a image file and find a hidden message in the file. I have to print the message on the console.
i think the part where i open the file and search for the hidden message is right, but i don´t know for sure because i can´t print the output to confirm.
this is the code:
; Example program to demonstrate file I/O.
; This example will open/create a file, write some
; information to the file, and close the file.
; Note, the file name is hard-coded for this example.
; This example program will open a file, read the
; contents, and write the contents to the screen.
; This routine also provides some very simple examples
; regarding handling various errors on system services.
; -------------------------------------------------------
section .data
; -----
; Define standard constants.
LF equ 10 ; line feed
NULL equ 0 ; end of string
TRUE equ 1
FALSE equ 0
EXIT_SUCCESS equ 0 ; success code
STDIN equ 0 ; standard input
STDOUT equ 1 ; standard output
STDERR equ 2 ; standard error
SYS_write equ 1; write
SYS_read equ 0 ; read
SYS_open equ 2 ; file open
SYS_close equ 3 ; file close
SYS_exit equ 60 ; terminate
SYS_creat equ 85 ; file open/create
SYS_time equ 201 ; get time
O_CREAT equ 0x40
O_TRUNC equ 0x200
O_APPEND equ 0x400
O_RDONLY equ 000000q ; read only
O_WRONLY equ 000001q ; write only
S_IRUSR equ 00400q
S_IWUSR equ 00200q
S_IXUSR equ 00100q
; -----
; Variables/constants for main.
BUFF_SIZE equ 256
newLine db LF, NULL
db LF, LF, NULL
fileName dq 6
fileDesc dq 0
errMsgOpen db "Error opening the file.", LF, NULL
errMsgRead db "Error reading from the file.", LF, NULL
offset db 1
size db 1
; -------------------------------------------------------
section .bss
readBuffer: resb BUFF_SIZE
; -------------------------------------------------------
section .text
global _start
_start:
xor rax, rax
xor rcx, rcx
xor rdx, rdx
xor rbx, rbx
mov rbx, rsp
mov rax, qword [rbx+16]
mov [fileName], rax
xor rax, rax
push rsp
; Attempt to open file - Use system service for file open
openInputFile:
pop rax ; pop argc value - should be 2
cmp rax, 0x2
jne done
mov rax, SYS_open ; file open
mov rdi, fileName ; file name string
mov rsi, O_RDONLY ; read only access
syscall ; call the kernel
cmp rax, 0 ; check for success
jl errorOnOpen
mov qword [fileDesc], rax ; save descriptor
; -----
; Read from file.
;
mov rax, SYS_read
mov rdi, qword [fileDesc]
mov rsi, readBuffer
mov rdx, BUFF_SIZE
syscall
cmp rax, 0
jl errorOnRead
; -----
; Print the buffer.
; add the NULL for the print string
mov rax, qword [readBuffer+2] ;SSSS
mov qword [size], rax
mov rax, qword [readBuffer+10] ;OOOO
mov [offset], rax
mov rcx, 0
ler: ;ler um caracter
mov rbp, 0
xor rbx, rbx
xor rdx, rdx
lerloop:
inc rax
cmp rax, [size]
je errorOnRead
saltaQuartobyte:
inc ecx
cmp ecx, 4
jne continua
inc rax ;incremneta rax outra vez para saltar o quarto
cmp rax, [size]
je errorOnRead
mov ecx, 0
continua:
mov bl, byte [readBuffer+rax]
shl rdx, 1
shr rbx, 1
adc rdx, 0
inc rbp
cmp rbp, 7 ;fim do caracter ASCII, 0X 0XXX XXXX
jne lerloop
mov rdi, rdx
call printString ; imprime caracter ASCII
cmp rax, [size] ;comea o priximo
jne ler
; -----
; Close the file.
mov rax, SYS_close
mov rdi, qword [fileDesc]
syscall
jmp done
; -----
; Error on open.
errorOnOpen:
mov rdi, errMsgOpen
call printString
jmp done
; Error on read.
errorOnRead:
mov rdi, errMsgRead
call printString
jmp done
; -----
; program done.
done:
mov rax, SYS_exit
mov rdi, EXIT_SUCCESS
syscall
; **********************************************************
; Generic procedure to display a string to the screen.
global printString
printString:
push rbp
mov rbp, rsp
push rbp
; -----
; Call OS to output string.
mov rax, SYS_write ; code for write()
mov rsi, rdi ; addr of characters
mov rdi, STDOUT ; file descriptor
; count set above
syscall ; system call
; -----
; String printed, return to calling routine.
prtDone:
pop rbx
pop rbp
ret
this is my last attempt of the print but the program still don't print anything, and I don't understand why? or what's wrong?
A fundamental error
push rsp
; Attempt to open file - Use system service for file open
openInputFile:
pop rax ; pop argc value - should be 2
cmp rax, 0x2
jne done
mov rax, SYS_open ; file open
Your program starts with copying the stackpointer RSP to the accumulator RAX, and then compares to see if the value is 2, but when is the stackpointer ever going to be 2? And so, the program will always prematurely exit. No wonder that nothing gets printed.
A selection of other errors
offset db 1
size db 1
...
mov rax, qword [readBuffer+2] ;SSSS
mov qword [size], rax
mov rax, qword [readBuffer+10] ;OOOO
mov [offset], rax
You have reserved not enough room to store the qwords size and offset!
Better store them in the .bss section using resq:
section .bss
readBuffer: resb BUFF_SIZE
offset resq 1
size resq 1
mov rax, qword [readBuffer+2] ;SSSS
mov qword [size], rax
mov rax, qword [readBuffer+10] ;OOOO
mov [offset], rax
If the file is a .BMP (I'm considering those well-known offsets), then the size and offset fields are actually dwords. You would have to write instead (loading EAX automatically zero extends the value into RAX):
mov eax, [readBuffer+2] ;SSSS
mov [size], rax
mov eax, [readBuffer+10] ;OOOO
mov [offset], rax
printString:
push rbp
mov rbp, rsp
push rbp <<<<
...
pop rbx <<<<
pop rbp
ret
Because of the mismatch, you're destroying RBX on return.
The code that you used depends on calculating the length of the ASCIIZ string. You cannot just leave that out!

Windows multicore program worked before but suddenly threads execute randomly

Below is a multithreaded (4-core) NASM 64 program. It's not minimal, but it's complete; I posted the complete code because a minimal example may not reveal the problem in this code.
This is my first multithreaded multicore program in NASM, and I was happy to see yesterday afternoon that it worked correctly (all four cores) and returned the values I was expecting. I ran it successfully several times yesterday and again several times this morning.
Suddenly, about 10 minutes after my last run, without making any changes to the code, without re-assembling the dll, I ran it again and this time the threads execute randomly -- not all threads execute, and the configuration of threads that execute varies from run to run -- sometimes thread 1 only; sometimes threads 2-4 but not thread 1, sometimes only thread 2 and 4, etc.
My code did not have ExitThread or CloseHandle calls, so I added them in (see label_899:), rebooted and ran it again. The first run after a fresh reboot still shows random execution of threads.
I thought the problem may be that CreateThread was failing, so I also returned the thread handles. Every time, all four thread handles were created even though all did not execute, so that's not it.
I have done a lot of research but I haven't seen this issue discussed at all. Even though this is NASM, the same thing could also be applicable to C or C++ multithreading. I use WaitForMultipleObjects to wait on all threads to complete.
This is a dll, and the entry point is Main_Entry_fn. The dll is called from Python using ctypes, but I doubt that makes any difference. I use ctypes frequently and have never had a problem with it.
Thanks for any ideas.
P.S. ignore the realloc code because the buffers are large enough that realloc is never called.
UPDATE: Here is how I constructed the progam flow: the entry point is Main_Entry_fn toward the bottom of the program listing (it's an export because it has to be exported for a dll call). Main_Entry_fn takes the input data from the calling function, preserves registers (because the whole program is register optimized) and allocates output buffers. Main_Entry_fn then calls Init_Cores_fn (top of program listing), where we create four arrays with data for the registers on entry to each core (remember all vars are stored in registers -- see the call to DupThreadInfo), and creates four threads in a loop. The threads all call Prime_Number_fn, and the threads are set to start immediately upon creation.
Register assignments:
r15 list_of_results_ptr (pointer to list_of_results)
r14 list_of_results_ctr (counter for list_of_results)
r13 list_of_results_length
r12 numbers_ptr (pointer to "numbers" input array)
r11 numbers_ctr
r10 numbers_length
r9 num
r8 i
xmm15 num_float
xmm14: result
; Header Section
[BITS 64]
[default rel]
extern malloc, calloc, realloc, free
global Main_Entry_fn
export Main_Entry_fn
global FreeMem_fn
export FreeMem_fn
extern CreateThread, CloseHandle, ExitThread
extern WaitForMultipleObjects, GetCurrentThread
section .data align=16
Return_Pointer_Array: dq 0, 0, 0
Input_Length_Array: dq 0, 0,
list_of_results_ptr: dq 0
list_of_results_ctr: dq 0
list_of_results_length: dq 0
data_master_ptr: dq 0
initial_dynamic_length: dq 0
internal_dynamic_length: dq 5000
XMM_Stack: dq 0, 0, 0
numbers_ptr: dq 0
numbers_length: dq 0
numbers: dq 0
list_of_results: dq 0
num_float: dq 0.0
loop_counter_401: dq 0
numbers_ctr: dq 0
num: dq 0
result: dq 0
const_1: dq 1
i: dq 0
range_loop_start_i: dq 0
range_loop_end_i: dq 0
const_0: dq 0
; New vars for threads:
ThreadCount: times 4 dq 0
ThreadInfo: times 10 dq 0
ThreadInfo2: times 10 dq 0
ThreadInfo3: times 10 dq 0
ThreadInfo4: times 10 dq 0
TestInfo: times 4 dq 0
ThreadHandles: times 4 dq 0
Return_Data_Array: times 8 dq 0 ; ptr,ptr,ptr,ptr,length,length,length,length
StartByte: dq 0
stride: dq 8
output_buffer_pointers: times 4 dq 0 ; for malloc
Division_Size: dq 0
Division_Start: dq 0
section .text
; ______________________________________
Init_Cores_fn:
; Calculate the data divisions
mov rax,r10
mov rbx,4 ;cores
xor rdx,rdx
div rbx
mov [Division_Size],rax
mov [Division_Start],rax
; Populate the ThreadInfo array with vars to pass
; ThreadInfo: length, startbyte, stride, vars into registers on entry to each core
mov rdi,ThreadInfo
mov rax,0 ;ThreadInfoLength
mov [rdi],rax ; length (number of vars into registers plus 3 elements)
mov rax,[stride]
mov [rdi+16],rax ; 8 x number of cores (32 in this example)
; Vars (these registers are populated on main entry)
mov rbp,output_buffer_pointers
mov rax,[rbp]
mov [rdi+24],rax ;for r15
mov [rdi+32],r14
mov [rdi+40],r13
mov [rdi+48],r12
mov rax,[Division_Start]
mov [rdi+56],rax
mov rax,0
mov [rdi+64],rax
call DupThreadInfo
mov rbp,rsp ; preserve caller's stack frame
sub rsp,56 ; Shadow space (was 32)
; _____
label_0:
mov rax,[StartByte]
cmp rax,0
jne sb2
mov rdi,ThreadInfo
jmp sb5
sb2:cmp rax,8
jne sb3
mov rdi,ThreadInfo2
jmp sb5
sb3:cmp rax,16
jne sb4
mov rdi,ThreadInfo3
jmp sb5
sb4:cmp rax,24
jne sb5
mov rdi,ThreadInfo4
sb5:
; _____
; Create Threads
mov rcx,0 ; lpThreadAttributes (Security Attributes)
mov rdx,0 ; dwStackSize
mov r8,PrimeNumber_fn ; lpStartAddress (function pointer)
mov r9,rdi ; lpParameter (array of data passed to each core)
mov rax,0
mov [rsp+32],rax ; use default creation flags
mov rdi,ThreadCount
mov [rsp+40],rdi ; ThreadID
call CreateThread
; Move the handle into ThreadHandles array (returned in rax)
mov rdi,ThreadHandles
mov rcx,[StartByte]
mov [rdi+rcx],rax
mov rax,[StartByte]
add rax,8
mov [StartByte],rax
mov rbx,32 ; Four cores
cmp rax,rbx
jl label_0
; _____
; Wait
mov rcx,4 ;rax ; number of handles
mov rdx,ThreadHandles ; pointer to handles array
mov r8,0 ; wait for all threads to complete
mov r9,5000 ; milliseconds to wait
call WaitForMultipleObjects
; _____
mov rsp,rbp
jmp label_900
; ______________________________________
PrimeNumber_fn:
; Populate registers
;(note: rcx is the return value for ThreadProc)
mov rdi,rcx
mov rax,[rdi]
mov r15,[rdi+24]
mov r13,[rdi+40]
mov r12,[rdi+48]
mov r10,[rdi+56]
xor r11,r11
xor r9,r9
mov r8,[rdi+8] ; start byte
pxor xmm15,xmm15
pxor xmm15,xmm14
pxor xmm15,xmm13
; Get the ThreadID based on startbyte
mov rax,[rdi+72] ; 0, 8, 16, 24 for 4-core
push rax
;______
label_401:
mov rdi,r12 ; Pointer
cmp r8,r10
jge label_899
movsd xmm0,qword[rdi+r8]
movsd xmm15,xmm0
add r8,8
;______
cvttsd2si rax,xmm15
mov r9,rax
;______
label_8010:
label_801:
cmp r9,[const_1]
jle label_401
;______
label_12010:
mov rax,2
sub rax,1
movq xmm13,rax
label_1201:
movq rcx,xmm13
movq xmm1,[const_1]
addsd xmm13,xmm1
movq rcx,xmm13
mov rdx,r9
cmp rcx,rdx
jge label_12020
;______
label_16010:
label_1601:
mov rax,r9
movq rbx,xmm13
xor rdx,rdx
div rbx
mov rax,rdx
mov rdx,0
cmp rax,rdx
jne label_16020
;______
movq xmm14,[const_0]
;______
movq rax,xmm14
cvtsi2sd xmm0,rax
movsd [r15+r14],xmm14
add r14,8
mov rax,r13
cmp r14,rax
jl next_17
;[Irrelevant code omitted]
next_17:
;______
jmp label_401
;______
label_1602:
label_16020:
;______
mov rax,r9
cvtsi2sd xmm14,rax
;______
movq rax,xmm14
cvtsi2sd xmm0,rax
movsd [r15+r14],xmm14
add r14,8
mov rax,r13
cmp r14,rax
jl next_21
;[Irrelevant code omitted]
next_21:
jmp label_1201
;______
label_1202:
label_12020:
;______
movq xmm14,[const_0]
;______
movq rax,xmm14
cvtsi2sd xmm0,rax
movsd [r15+r14],xmm14
add r14,8
mov rax,r13
cmp r14,rax
jl next_25
;[Irrelevant code omitted]
next_25:
jmp label_401
;______
label_899:
pop rax
mov rdi,Return_Data_Array
mov [rdi+rax],r15
mov [rdi+rax+32],r14 ; 32 = four cores
call ExitThread
call GetCurrentThread
mov rcx,rax
call CloseHandle
ret
; __________
label_900:
exit_label_for_PrimeNumber_fn:
mov rdi,Return_Data_Array ; Final return to the calling process
mov rax,rdi
ret
;__________
;Free the memory
FreeMem_fn:
sub rsp,40
call free
add rsp,40
ret
; __________
; Main Entry
Main_Entry_fn:
push rdi
push rbp
push rbx
push r15
xor r15,r15
push r14
xor r14,r14
push r13
xor r13,r13
push r12
xor r12,r12
push r11
xor r11,r11
push r10
xor r10,r10
push r9
xor r9,r9
movsd [XMM_Stack+0],xmm15
movsd [XMM_Stack+8],xmm14
movsd [XMM_Stack+16],xmm13
push r8
xor r8,r8
mov [numbers_ptr],rcx
mov [data_master_ptr],rdx
; Now assign lengths
lea rdi,[data_master_ptr]
mov rbp,[rdi]
xor rcx,rcx
movsd xmm0,qword[rbp+rcx]
cvttsd2si rax,xmm0
mov [numbers_length],rax
add rcx,8
; __________
; malloc for dynamic arrays
lea rdi,[data_master_ptr]
mov rbp,[rdi]
movsd xmm0,qword[rbp]
cvttsd2si rax,xmm0
mov r8,rax
mov rdx,10
mul rdx
mov rdx,10000000
cmp rax,rdx
jl malloc_next
mov rax,r8
malloc_next:
mov rax,50000000
mov [initial_dynamic_length],rax
;__________
; Output buffer #1
mov rcx,qword[initial_dynamic_length] ; Initial size
xor rax,rax
sub rsp,40
call malloc
mov rdi,output_buffer_pointers
mov [rdi],rax
add rsp,40
mov rax,qword[initial_dynamic_length]
mov [list_of_results_length],rax
;__________
; Output buffer #2
mov rcx,qword[initial_dynamic_length] ; Initial size
xor rax,rax
sub rsp,40
call malloc
mov rdi,output_buffer_pointers
mov [rdi+8],rax
add rsp,40
mov rax,qword[initial_dynamic_length]
mov [list_of_results_length],rax
;__________
; Output buffer #3
mov rcx,qword[initial_dynamic_length] ; Initial size
xor rax,rax
sub rsp,40
call malloc
mov rdi,output_buffer_pointers
mov [rdi+16],rax
add rsp,40
mov rax,qword[initial_dynamic_length]
mov [list_of_results_length],rax
;__________
; Output buffer #4
mov rcx,qword[initial_dynamic_length] ; Initial size
xor rax,rax
sub rsp,40
call malloc
mov rdi,output_buffer_pointers
mov [rdi+24],rax
add rsp,40
mov rax,qword[initial_dynamic_length]
mov [list_of_results_length],rax
; __________
; Write variables to assigned registers
lea rdi,[rel list_of_results_ptr]
mov r15,qword[rdi]
mov r14,[list_of_results_ctr]
mov r13,[list_of_results_length]
lea rdi,[rel numbers_ptr]
mov r12,qword[rdi]
mov r11,[numbers_ctr]
mov r10,[numbers_length]
mov r9,[num]
movsd xmm15,[num_float]
movsd xmm14,[result]
movsd xmm13,[i]
mov r8,[loop_counter_401]
; __________
call Init_Cores_fn
exit_label_for_Main_Entry_fn:
pop r8
movsd xmm13,[XMM_Stack+0]
movsd xmm14,[XMM_Stack+8]
movsd xmm15,[XMM_Stack+16]
pop r9
pop r10
pop r11
pop r12
pop r13
pop r14
pop r15
pop rbx
pop rbp
pop rdi
ret
;_____________
DupThreadInfo:
mov rdi,ThreadInfo2
; StartByte and EndByte
mov rax,[Division_Start]
mov [rdi+8],rax
add rax,[Division_Size]
mov [Division_Start],rax
sub rax,8
mov [rdi+56],rax
mov rax,[stride]
mov [rdi+16],rax ; 8 x number of cores (32 in this example)
; Vars (these registers are populated on main entry)
mov rbp,output_buffer_pointers
mov rax,[rbp+8]
mov [rdi+24],rax
mov rax,8
mov [rdi+32],rax
mov [rdi+40],r13
mov [rdi+48],r12
; 56 is above
mov rax,8
mov [rdi+64],rax
mov rax,8 ; Thread number based on startbyte, for Return_Data_Array
mov [rdi+72],rax
; _____
mov rdi,ThreadInfo3
; StartByte and EndByte
mov rax,[Division_Start]
mov [rdi+8],rax
mov rbx,[Division_Size]
add rax,rbx
mov [Division_Start],rax
sub rax,8
mov [rdi+56],rax
mov rax,[stride]
mov [rdi+16],rax ; 8 x number of cores (32 in this example)
; Vars (these registers are populated on main entry)
mov rbp,output_buffer_pointers
mov rax,[rbp+16]
mov [rdi+24],rax
mov rax,16
mov [rdi+32],rax
mov [rdi+40],r13
mov [rdi+48],r12
; [rdi+56] is above
mov rax,16
mov [rdi+64],rax
mov rax,16 ; Thread number based on startbyte, for Return_Data_Array
mov [rdi+72],rax
mov rdi,ThreadInfo4
; StartByte and EndByte
mov rax,[Division_Start]
mov [rdi+8],rax
mov rax,[numbers_length] ; final segment goes to the end
mov [rdi+56],rax
mov rax,[stride]
mov [rdi+16],rax ; 8 x number of cores (32 in this example)
; Vars (these registers are populated on main entry)
mov rbp,output_buffer_pointers
mov rax,[rbp+24]
mov [rdi+24],rax
mov rax,24
mov [rdi+32],rax
mov [rdi+40],r13
mov [rdi+48],r12
; [rdi+56] is above
mov rax,24
mov [rdi+64],rax
mov rax,24 ; Thread number based on startbyte, for Return_Data_Array
mov [rdi+72],rax
ret

x86-64 Bit Assembly Linux Input

I'm trying to input into my program... All it does is run through and print a '0' to the screen. I'm pretty sure that the PRINTDECI function works, I made it a while ago and it works. Do I just have to loop over the input code and only exit when I enter a certain value? I'm not sure how I would do that... Unless it's by ACSII values which might suck.... Anyways, here's my code (Yasm(nasm clone), Intel Syntax):
GLOBAL _start
SECTION .text
PRINTDECI:
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 CHECK_BUFFER
MOV byte [R9],DL ; save remainder
SUB R9,1 ; decrement the buffer address
JMP DIV_BY_10
CHECK_BUFFER:
MOV byte [R9],DL
SUB R9,1
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
_start:
MOV RCX, SCORE ;Input into Score
MOV RDX, SCORELEN
MOV RAX, 3
MOV RBX, 0
SYSCALL
MOV RAX, [SCORE]
PUSH RAX ;Print Score
CALL PRINTDECI
POP RAX
MOV RAX,60 ;Kill the Code
MOV RDI,0
SYSCALL
SECTION .bss
SCORE: RESQ 1
SCORELEN EQU $-SCORE
Thanks for any help!
- Kyle
As a side note, the pointer in RCX goes to a insanely large number according to DDD... So I'm thinking I have to get it to pause and wait for me to type, but I have no idea how to do that...
The 'setup' to call syscall 0 (READ) on x86_64 system is:
#xenon:~$ syscalls_lookup read
read:
rax = 0 (0x0)
rdi = unsigned int fd
rsi = char *buf
rdx = size_t count
So your _start code should be something like:
_start:
mov rax, 0 ; READ
mov rdi, 0 ; stdin
mov rsi, SCORE ; buffer
mov rdx, SCORELEN ; length
syscall
The register conventions and syscall numbers for x86_64 are COMPLETELY different than those for i386.
Some conceptual issues you seem to have:
READ does not do ANY interpretation on what you type, you seem to be expecting it to let you type a number (say, 57) and have it return the value 57. Nope. It'll return '5', '7', 'ENTER', 'GARBAGE'... Your SCORELEN is probably 8 (length of resq 1), so you'll read, AT MOST, 8 bytes. or Characters, if you wish to call them that. And unless you type the EOF char (^D), you'll need to type those 8 characters before the READ call will return to your code.
You have to convert the characters you receive into a value... You can do it the easy way and link with ATOI() in the C library, or write your own parser to convert the characters into a value by addition and multiplication (it's not hard, see code below).
Used below, here as a reference:
#xenon:~$ syscalls_lookup write
write:
rax = 1 (0x1)
rdi = unsigned int fd
rsi = const char *buf
rdx = size_t count
Ugh.... So many... I'll just rewrite bits:
global _start
section .text
PRINTDECI:
; input is in RAX
lea r9, [NUMBER + NUMBERLEN - 1 ] ; + space for \n
mov r10, r9 ; save end position for later
mov [r9], '\n' ; store \n at end
dec r9
mov rbx, 10 ; base10 divisor
DIV_BY_10:
xor rdx, rdx ; zero rdx for div
div rbx : rax = rdx:rax / rbx, rdx = remainder
or dl, 0x30 ; make REMAINDER a digit
mov [r9], dl
dec r9
or rax, rax
jnz DIV_BY_10
PRINT_BUFFER:
sub r10, r9 ; get length (r10 - r9)
inc r9 ; make r9 point to initial character
mov rax, 1 ; WRITE (1)
mov rdi, 1 ; stdout
mov rsi, r9 ; first character in buffer
mov rdx, r10 ; length
syscall
ret
MAKEVALUE:
; RAX points to buffer
mov r9, rax ; save pointer
xor rcx, rcx ; zero value storage
MAKELOOP:
mov al, [r9] ; get a character
or al, al ; set flags
jz MAKEDONE ; zero byte? we're done!
and rax, 0x0f ; strip off high nybble and zero rest of RAX (we're lazy!)
add rcx, rcx ; value = value * 2
mov rdx, rcx ; save it
add rcx, rcx ; value = value * 4
add rcx, rcx ; value = value * 8
add rcx, rdx ; value = value * 8 + value * 2 (== value * 10)
add rcx, rax ; add new digit
jmp MAKELOOP ; do it again
MAKEDONE:
mov rax, rcx ; put value in RAX to return
ret
_start:
mov rax, 0 ; READ (0)
mov rdi, 0 ; stdin
mov rsi, SCORE ; buffer
mov rdx, SCORELEN ; length
syscall
; RAX contains HOW MANY CHARS we read!
; -OR-, -1 to indicate error, really
; should check for that, but that's for
; you to do later... right? (if RAX==-1,
; you'll get a segfault, just so you know!)
add rax, SCORE ; get position of last byte
movb [rax], 0 ; force a terminator at end
mov rax, SCORE ; point to beginning of buffer
call MAKEVALUE ; convert from ASCII to a value
; RAX now should have the VALUE of the string of characters
; we input above. (well, hopefully, right?)
mov [VALUE], rax ; store it, because we can!
; it's stored... pretend it's later... we need value of VALUE!
mov rax, [VALUE] ; get the VALUE
call PRINTDECI ; convert and display value
; all done!
mov rax, 60 ; EXIT (60/0x3C)
mov rdi, 0 ; exit code = 0
syscall
section .bss
SCORE: resb 11 ; 10 chars + zero terminator
SCORELEN equ $-SCORE
NUMBER: resb 19 ; 18 chars + CR terminator
NUMBERLEN equ $-NUMBER
I'm going to say that this should work first time, it's off-the-cuff for me, haven't tested it, but it should be good. We read up to 10 chars, terminate it with a zero, convert to a value, then convert to ascii and write it out.
To be more proper, you should save registers to the stack in each subroutine, well, certain ones, and really, only if you're going to interface with libraries... doing things yourself lets you have all the freedom you want to play with the registers, you just have to remember what you put where!
Yes, someone is going to say "why didn't you just multiply by 10 instead of weird adding?" ... uh... because it's easier on the registers and I don't have to set it all up in rdx:rax. Besides, it's just as readable and understandable, especially with the comments. Roll with it! This isn't a competition, it's learning!
Machine code is fun! Gotta juggle all the eggs in your head though... no help from the compiler here!
Technically, you should check return result (RAX) of the syscalls for READ and WRITE, handle errors appropriately, yadda yadda yadda.... learn to use your debugger (gdb or whatever).
Hope this helps.

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

Printing a number in x86-64 assembly

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

Resources