printing numbers in nasm - linux

I have written an assembly code to print numbers from 1 to 9 but the code only prints 1 and no other element other than 1 is printed and only one output is received.It means that the loop is also not being run. I cant figure out what is wrong with my code.
section .bss
lena equ 1024
outbuff resb lena
section .data
section .text
global _start
_start:
nop
mov cx,0
incre:
inc cx
add cx,30h
mov [outbuff],cx
cmp cx,39h
jg done
cmp cx,39h
jl print
print:
mov rax,1 ;sys_write
mov rdi,1
mov rsi,outbuff
mov rdx,lena
syscall
jmp incre
done:
mov rax,60 ;sys_exit
mov rdi,0
syscall
My OS is 64 bit linux. this code is built using nasm with the following commands : nasm -f elf64 -g -o num.o num.asm and ld -o num num.asm

Answer rewritten after some experimentation.
There two errors in your code, and a few inefficiencies.
First, you add 0x30 to the number (to turn it from the number 1 to the ASCII 1). However, you do that increment inside the loop. As a result, your first iteration cx is 0x31, second 0x62 ("b"), third 0x93 (invalid UTf-8 sequence) etc.
Just initialize cx to 0x30 and remove the add from inside the loop.
But there's another problem. RCX is clobbered during system calls. Replacing cx with r12 causes the program to work.
In addition to that, you pass the buffer's length to write, but it only has one character. The program so far:
section .bss
lena equ 1024
outbuff resb lena
section .data
section .text
global _start
_start:
nop
mov r12,30h
incre:
inc r12
mov [outbuff],r12
cmp r12,39h
jg done
cmp r12,39h
jl print
print:
mov rax,1 ;sys_write
mov rdi,1
mov rsi,outbuff
mov rdx,1
syscall
jmp incre
done:
mov rax,60 ;sys_exit
mov rdi,0
syscall
Except even now, the code is extremely inefficient. You have two compares on the same condition, one of them branches to the very next instruction.
Also, your code would be much much much faster and smaller if you moved the breaking condition to the end of the code. Also, cx is a 16 bit register. r12 is a 64 bit register. We actually only need 8 bits. Using larger registers than needed means all of our immediates waste up space in memory and the cache. We therefor switch to the 8 bit variant of r12. After these changes, we get:
section .bss
lena equ 1024
outbuff resb lena
section .data
section .text
global _start
_start:
nop
mov r12b,30h
incre:
inc r12b
mov [outbuff],r12b
mov rax,1 ;sys_write
mov rdi,1
mov rsi,outbuff
mov rdx,1
syscall
cmp r12b,39h
jl incre
mov rax,60 ;sys_exit
mov rdi,0
syscall
There's still lots more you can do. For example, you call the write system call 9 times, instead of filling the buffer and then calling it once (despite the fact that you've allocated a 1024 bytes buffer). It will probably be faster to initialize r12 with zero (xor r12, r12) and then add 0x30. (not relevant for the 8 bit version of the register).

Related

nasm linux x64 how do i find and cmp EOF to stop printing data from file to screen

nasm linux x64 how do i find and cmp EOF to stop printing data from file to screen
section .data
Nile_2 db '/home/mark/Desktop/mynewfile.txt', 0;
section .bss
fd_out resd 4 ; use this here instead of resb so there is enough room for long file names
fd_in resd 4
info resd 26
section .text
global _start ;must be declared for using gcc
_start:
;open the file for reading
mov rax, 5
mov rbx, Nile_2 ; was file_name
mov rcx, 0 ;for read only access
; mov rdx, 0777 ;read, write and execute by all
int 0x80
mov [fd_in], eax
;mov rdx, 20
READ:
;read from file
mov rax, 3
mov rbx, [fd_in]
mov rcx, info
;mov rdx, 26
int 0x80
; print the info
mov rax, 4
mov rbx, 1
mov rcx, info
;mov rdx, 26
int 0x80
mov r10, info ; dec rdx
cmp r10, 00
jnz READ
;jmp READ ;jnz Read
HERE:
; close the file
mov rax, 6
mov rbx, [fd_in]
int 0x80
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel
how do i find out if sys_read or info is zero
how do i find out EOF ??? i dont know how to use sys_read to check if no bytes have been read... when i try to cmp that info is zero bytes read i get the last few bytes over and over ???
You are using int 0x80 in your 64-bit code. Normally, in 64-bit code, you would use the syscall instruction and use other register arguments. For some light reading, see
What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code?
how do i find out if sys_read or info is zero how do i find out EOF ???
If a request to read a certain number of bytes from a file, reports a count that is less than the number that you requested, then the end-of-file has been reached. If the reported count is 0, then the end-of-file was already reached before you made the request, else we say that a partial record was read.
i dont know how to use sys_read to check if no bytes have been read...
sys_read provides you with the number of bytes that were actually read in the eax register. I mentioned this already in my answer to your previous question Nasm linux for some reason i cant use two file variable names at the same time for opening a file and creating a file?
when i try to cmp that info is zero bytes read i get the last few bytes over and over ???
You have managed to create an endless loop!
In NASM, an instruction like mov r10, info loads the address of info in the register. So not the contents that are stored at info which is what you were trying to get.
Since the address is not zero, code like:
mov r10, info
cmp r10, 00
jnz READ
will always jump and thus continue the loop ad infinitum.
fd_out resd 4 ; use this here instead of `resb` so there is **enough room for long file names**
fd_in resd 4
info resd 26
What sys_creat and sys_open return to you in the eax register is a file descriptor (it's in the names fd_in and fd_out), and it's a handle by which the system can identify the open file. It is a single dword and it is meaningless to assign 4 dwords for its storage.
Also, I find it strange that, in response to my previous answer, you changed info resb 26 into info resd 26. This does not make much sense.
With using 64-bit registers this time, you did introduce another mismatch on the fd_in variable! If you stored a dword (mov [fd_in], eax) then don't retrieve a qword (mov rbx, [fd_in])
section .bss
fd_out resd 1
fd_in resd 1
info resb 26
...
READ:
;read from file
mov edx, 26
mov ecx, info
mov ebx, [fd_in]
mov eax, 3
int 0x80 ; -> EAX
test eax, eax
js ERROR ; Some error occured
jz HERE ; End-of-file
; print the info
mov edx, eax ; Could be a partial record
mov ecx, info
mov ebx, 1
mov eax, 4
int 0x80
jmp READ
ERROR:
HERE:
i found out that if i check eax and if its zero thats the end of file
cmp rax, 0
je HERE
'''
so that there does the job and not it will end almost properly when it reaches the end of the file it does spit out an extra bit tho dont know why

Conditional jump fails in linux x86 intel syntax(NASM)

STORY(IM A NEWBIE):
I started reading a pdf tutorial about programming in assembly(x86 intel) using the famous nasm assembler and i have a problem executing a very basic assembly code(inspired by a code about loops from the tutorial).
THE PROBLEM(JE FAILS):
This assembly code should read a digit(a character(that means '0'+digit)) from stdin and then write to the screen digit times "Hello world\n".Really easy loop :decrease digit and if digit equals zero('0' not the integer the character) jump(je) to the exit(mov eax,1\nint 0x80).
Sounds really easy but when i try to execute the output is weird.(really weird and BIG)
It runs many times throught the loop and stops when digit equals '0'(weird because until the program stops the condition digit == '0' been tested many times and it should be true)
Actually my problem is that the code fails to jump when digit == '0'
THE CODE(IS BIG):
segment .text
global _start
_start:
;Print 'Input a digit:'.
mov eax,4
mov ebx,1
mov ecx,msg1
mov edx,len1
int 0x80
;Input the digit.
mov eax,3
mov ebx,0
mov ecx,dig
mov edx,2
int 0x80
;Mov the first byte(the digit) in the ecx register.
;mov ecx,0
mov ecx,[dig]
;Use ecx to loop dig[0]-'0' times.
loop:
mov [dig],ecx
mov eax,4
mov ebx,1
mov ecx,dig
mov edx,1
int 0x80
mov eax,4
mov ebx,1
mov ecx,Hello
mov edx,Hellolen
int 0x80
;For some debuging (make the loop stop until return pressed)
;mov eax,3
;mov ebx,0
;mov ecx,some
;mov edx,2
;int 0x80
;Just move dig[0](some like character '4' or '7') to ecx register and compare ecx with character '0'.
mov ecx,[dig]
dec ecx
cmp ecx,'0'
;If comparison says ecx and '0' are equal jump to exit(to end the loop)
je exit
;If not jump back to loop
jmp loop
;Other stuff ...(like an exit procedure and a data(data,bss) segment)
exit:
mov eax,1
int 0x80
segment .data
msg1 db "Input a digit:"
len1 equ $-msg1
Hello db ":Hello world",0xa
Hellolen equ $-Hello
segment .bss
dig resb 2
some resb 2
THE OUTPUT:
Input a digit:4
4:Hello world
3:Hello world
2:Hello world
1:Hello world
0:Hello world
...
...(many loops later)
...
5:Hello world
4:Hello world
3:Hello world
2:Hello world
1:Hello world
$
That is my question:What is wrong with this code?
Could you explain that ?
AND i dont need alternative codes that will magically(without explanation) run cause i try to learn(im a newbie)
That is my problem(and my first question in Stackoverflow.com )
ECX is 32 bit, a character is just 8 bit. Use a 8 bit register, such as CL instead of ECX.
As jester mentioned, ecx comes in as a character so you probably should use cl
loop:
mov [dig],cl
...
mov cl,[dig]
dec cl
cmp cl,'0'
jne loop
You can also load ecx with movzx which clears the top bits of the register (i.e. a zero-extedning load):
...
movzx ecx, byte [dig]
loop:
mov [dig], cl ; store just the low byte, if you want to store
...
movzx ecx, byte [dig]
dec ecx
cmp ecx, '0'
jne loop
Note that it is often suggested that you do not use the al, bl, cl, dl registers as their use is not fully optimized. Whether this is still true, I do not know.

strlen in NASM Linux

Excuse me again. I am trying understand learn assembly languaje. However I have many problems. I am trying working with strings in NASM. I have copy a string constant to string variable. The maximum size is 50. So I want verify this bound. However this program throw a segmentation fault. I use a example in MASM, so perhaps exist a use error with NASM syntax.
My program is the following:
section .data
MAXTEXTSIZE equ 50
_cte_hola db "Hola", 0
_cte_mundo db "Mundo", 0
section .bss
MAIN_d resb MAXTEXTSIZE+1
section .text
global _start
strlen:
mov bx, 0
strl01:
cmp WORD [SI+BX],0 t
je strend
inc bx
jmp strl01
strend:
ret
strcpy:
call strlen
cmp bx, MAXTEXTSIZE
jle copiarsizeok
mov bx, MAXTEXTSIZE
copiarsizeok:mov cx, bx
cld
rep movsb
mov al,0
mov BYTE [DI], al
ret
_start:
mov ds, ax
mov es, ax
mov si, [MAIN_d]
mov di, [_cte_hola]
call strcpy
mov eax, 1
mov ebx, 0
int 80h
Thanks in advance and excuse me. My question are stupid for a assembly programmer.
I believe you are trying to make 32bit program in Linux, but your examples are 16bit.
In Linux, all pointers are 32bit. So, use extended registers: esi, edi, ebx etc. You still can use 8 and 16bit registers for arithmetics and data processing but not as memory pointers.
In strlen you have to compare byte [esi+ebx], 0 not word.
Don't set the segment registers in Linux. They will be set by the OS and you can't touch them. In Linux all memory is one flat area and you don't have to use segment registers anymore.
Here's a more concrete example of how you could write your strlen function (which is the first of your problems)
section .data
MAXTEXTSIZE equ 50
_cte_hola db "Hola", 0xa, 0
_cte_mundo db "Mundo", 0
section .bss
MAIN_d resb MAXTEXTSIZE+1
section .text
global _start
strlen:
mov ebx, 0
strlen_loop:
cmp BYTE [esi+ebx], 0
je strlen_end
inc ebx
jmp strlen_loop
strlen_end:
mov eax, ebx
ret
_start:
mov esi, _cte_hola
call strlen ; Get the length of _cte_hola
mov edx, eax ; The length was stored in eax by strlen
mov ecx, _cte_hola
mov ebx,1
mov eax, 4
int 0x80 ; Write to stdout
mov eax, 1
int 0x80 ; Exit
There are definitely better ways of implementing this (I'd use repne to implement strlen, for example) but I wanted to keep it close to your implementation.
Hope this helps!

NASM addition program

I am a developer who uses high level languages, learning assembly language in my spare time. Please see the NASM program below:
section .data
section .bss
section .text
global main
main:
mov eax,21
mov ebx,9
add eax,ebx
mov ecx,eax
mov eax,4
mov ebx,1
mov edx,4
int 0x80
push ebp
mov ebp,esp
mov esp,ebp
pop ebp
ret
Here are the commands I use:
ian#ubuntu:~/Desktop/NASM/Program4$ nasm -f elf -o asm.o SystemCalls.asm
ian#ubuntu:~/Desktop/NASM/Program4$ gcc -o program asm.o
ian#ubuntu:~/Desktop/NASM/Program4$ ./program
I don't get any errors, however nothing is printed to the terminal. I used the following link to ensure the registers contained the correct values: http://docs.cs.up.ac.za/programming/asm/derick_tut/syscalls.html
You'll have to convert the integer value to a string to be able to print it with sys_write (syscall 4). The conversion could be done like this (untested):
; Converts the integer value in EAX to a string in
; decimal representation.
; Returns a pointer to the resulting string in EAX.
int_to_string:
mov byte [buffer+9],0 ; add a string terminator at the end of the buffer
lea esi,[buffer+9]
mov ebx,10 ; divisor
int_to_string_loop:
xor edx,edx ; clear edx prior to dividing edx:eax by ebx
div ebx ; EAX /= 10
add dl,'0' ; take the remainder of the division and convert it from 0..9 -> '0'..'9'
dec esi ; store it in the buffer
mov [esi],dl
test eax,eax
jnz int_to_string_loop ; repeat until EAX==0
mov eax,esi
ret
buffer: resb 10
programming in assembly requires a knowledge of ASCII codes and a some basic conversion routines. example: hexadecimal to decimal, decimal to hexadecimal are good routines to keep somewhere on some storage.
No registers can be printed as they are, you have to convert (a lot).
To be a bit more helpfull:
ASCII 0 prints nothing but some text editors (kate in kde linux) will show something on screen (a square or ...). In higher level language like C and C++ is it used to indicate NULL pointers and end of strings.
Usefull to calculate string lengths too.
10 is end of line. depending Linux or Windows there will be a carriage return (Linux) too or not (Windows/Dos).
13 is carriage return
1B is the ESC key (Linux users will now more about this)
255 is a hard return, I never knew why it is good for but it must have its purpose.
check http://www.asciitable.com/ for the entire list.
Convert the integer value to a string.
Here i have used macros pack and unpack to convert integers to string and macro unpack to do the vice-versa
%macro write 2
mov eax, 4
mov ebx, 1
mov ecx, %1
mov edx, %2
int 80h
%endmacro
%macro read 2
mov eax,3
mov ebx,0
mov ecx,%1
mov edx,%2
int 80h
%endmacro
%macro pack 3 ; 1-> string ,2->length ,3->variable
mov esi, %1
mov ebx,0
%%l1:
cmp byte [esi], 10
je %%exit
imul ebx,10
movzx edx,byte [esi]
sub edx,'0'
add ebx,edx
inc esi
jmp %%l1
%%exit:
mov [%3],ebx
%endmacro
%macro unpack 3 ; 1-> string ,2->length ,3->variable
mov esi, %1
mov ebx,0
movzx eax, byte[%3]
mov byte[%2],0
cmp eax, 0
jne %%l1
mov byte[%2],1
push eax
jmp %%exit2
%%l1:
mov ecx,10
mov edx,0
div ecx
add edx,'0'
push edx
inc byte[%2]
cmp eax, 0
je %%exit2
jmp %%l1
%%exit2:
movzx ecx,byte[%2]
%%l2:
pop edx
mov [esi],dl
inc esi
loop %%l2
%endmacro
section .data ; data section
msg1: db "First number : " ;
len1: equ $-msg1 ;
msg2: db "Second number : " ;
len2: equ $-msg2 ;
msg3: db "Sum : " ;
len3: equ $-msg3 ;
ln: db 10
lnl: equ $-ln
var1: resb 10
var2: resb 10
str1: resb 10
str2: resb 10
ans: resb 10
ansvar: resb 10
ansl: db ''
l1: db ''
l2: db ''
section.text ;code
global _start
_start:
write msg1,len1
read str1,10
pack str1,l1,var1
write msg2,len2
read str2,10
pack str2,l2,var2
mov al,[var1]
add al,[var2]
mov [ansvar],al
unpack ans,ansl,ansvar
write msg3,len3
write ans,10
write ln,lnl
mov ebx,0 ; exit code, 0=normal
mov eax,1 ; exit command to kernel
int 0x80 ; interrupt 80 hex, call kernel
To assembler, link and run:
nasm -f elf add.asm
ld -s -o add add.o
./add

Segfault accessing BSS memory

section .data
bufChar: equ 0
section .bss
bufNum: resb 1
bufMult: resb 1
.
.
.
leerNumero:
xor eax,eax
mov [bufNum],eax
add eax,1
mov [bufMult],eax
inicioLeerNumero:
mov edx,1
mov ecx,bufChar
mov ebx,0
mov eax,3
int 80h
cmp byte [ecx + edx - 1],10 ; Segfaults here.
je rLeerNumero
cmp byte [ecx + edx - 1],48
jl noNumero
cmp byte [ecx + edx - 1],57
jg noNumero
sub eax,48
mul word [bufMult]
jo overflow
add [bufNum],eax
jo overflow
mov eax,10
mul word [bufMult]
jo overflow
mov [bufMult],eax
jmp inicioLeerNumero
rLeerNumero:
mov eax,bufNum
ret
noNumero:
mov eax,errorNumero
mov ebx,lErrorNumero
call imprimir
jmp salir
overflow:
mov eax,errorOverflow
mov ebx,lErrorOverflow
call imprimir
jmp salir
This code should of work, at least in paper it does. I need to do some homework completely in assembly without linking the C Library, hence why i am re-inventing the wheel and making a method to read a number from the console into EAX.
I am having a mysterious segfault at the line marked with the comment and i fail to see how i coud be trying to access misaligned memory... any ideas on how could this be failing?
Any chance that int 80h is changing ecx or edx on you causing a bad pointer read? If you can read the registers in a debugger before and after that instruction, you could confirm that.
I had declared bufChar as .data, obviously mov'ing into a constant would segfault the thing. Sadly, i wasted a week wrapping my head around this, just realized so.

Resources