Print an integer NASM - arrays

I'm trying to read 3 numbers from the user and I store them in an array then I show them using paul carter functions in NASM here is my code :
%include "asm_io.inc"
SECTION .bss
tab resb 3
SECTION .data
msg db "Un nombre :",10
SECTION .text
global main
main:
mov esi,tab
xor ecx,ecx
get_data:
mov eax,msg
call print_string
call read_int
mov [esi+ecx],eax
inc ecx
cmp ecx,3
jne get_data
call print_nl
xor ecx,ecx
mov edi,tab
print_data:
mov eax,[edi+ecx]
call print_int
inc ecx
cmp ecx,3
jne print_data
mov eax,1 ; exit code
int 0x80 ; call exit
The problem is that is doesn't execute print_data loop and it exit .

Just to be clear. Are these the changes you did? Even if the ECX register is not used as an input or output for a particular function it might still be used internally. That's what Michael meant with 'ecx is typically caller-saved'
%include "asm_io.inc"
SECTION .bss
tab resd 3
SECTION .data
msg db "Un nombre :",10,0
SECTION .text
global main
main:
mov edi,tab
xor ecx,ecx
get_data:
push ecx
mov eax,msg
call print_string
call read_int
mov [edi+ecx*4],eax
pop ecx
inc ecx
cmp ecx,3
jne get_data
call print_nl
mov esi,tab
xor ecx,ecx
print_data:
push ecx
mov eax,[esi+ecx*4]
call print_int
pop ecx
inc ecx
cmp ecx,3
jne print_data
mov eax,1 ; exit code
int 0x80 ; call exit

Related

Print array in Asembly x86

I have elements loaded in stack and I need to move them to array. My code looks like this:
%include "asm_io.inc"
segment .data
array db 100 dup(0)
length db 0
segment .text
global _asm_main
extern getchar
_asm_main:
enter 0, 0
pusha
call getchar
char_loop:
mov ebx,10
sub eax, '0'
mul ebx
mov ebx, eax
call getchar
sub eax, '0'
add eax, ebx
push eax
inc BYTE[length]
call getchar
cmp eax, 10
je fill_array
cmp eax, 13
je fill_array
cmp eax, 32
je skip_spaces
jmp char_loop
skip_spaces:
call getchar
cmp eax, 32
je skip_spaces
jmp char_loop
fill_array:
mov ecx, [length]
mov ebx, array
l1:
pop eax
mov [ebx], eax ; should be al instead of eax
inc ebx
call print_int
call print_nl
loop l1
print_array:
mov ecx, [length]
mov ebx, array
l2:
mov eax, [ebx] ; should be al instead of eax
call print_int
call print_nl
inc ebx
loop l2
_asm_end:
call print_nl
popa
mov eax, 0
leave
ret
print_int in asm_io.asm is
print_int:
enter 0,0
pusha
pushf
push eax
push dword int_format
call _printf
pop ecx
pop ecx
popf
popa
leave
ret
Where int_format is int_format db "%i",0
Length and values in stack are correct, I had them printed but when I try to print array only last value is correct. Other values are random numbers. I tried combinations of registers of different sizes but it did not work. I think that error has to do something with size of registers or size of array.
Answer here:
As #xiver77 said in comments I was writing into array 4 bytes instead 1 byte. One element in array has 1 byte and I tried to write 4 bytes. That creates overflow of bites and change other elements in array. Instead mov [ebx], eax should be mov [ebx], al and mov eax, [ebx] for printing should be mov al [ebx].

Swapping the first and last element in the array using assembly

segment .data
array: db 68,222,29,68,33,234,179,103,37,85
fmt: db ",%d",0
segment .text
extern printf
global asm_main
asm_main:
enter 0,0 ; setup routine
pusha
push dword 10
push dword array
call print_array
add esp,8
push dword 10
push dword array
swap_byte_first_last:
mov eax,[array]
mov edx,[array+9]
mov [array+9],eax
mov [array],edx
call print_array
; don't delete anything following this comment
popa
mov eax, 0 ; return back to C
leave
ret
segment .data
ListFormat db ",%u", 0
segment .text
global print_array
print_array:
enter 0,0
push esi
push ebx
xor esi, esi
mov ecx, [ebp+12]
mov ebx, [ebp+8]
xor edx,edx
mov dl,[ebx + esi]
mov eax,edx
call print_int
dec ecx
inc esi
print_loop:
xor edx,edx
mov dl,[ebx + esi]
push ecx
push edx
push dword ListFormat
call printf
add esp, 8
inc esi
pop ecx
loop print_loop
call print_nl
pop ebx
pop esi
leave
ret
%define A_ADDR [ebp+12]
%define B_ADDR [ebp+8]
%define A_VAL [eax]
%define B_VAL [ebx]
segment .text
global swap_byte
swap_byte:
enter 0,0
pusha
mov eax, A_ADDR
mov ebx, B_ADDR
mov dl,A_VAL
mov cl,B_VAL
mov [eax],cl
mov [ebx],dl
popa
leave
ret
This prints 85,44,37,100,33,234,179,103,37,68. The result should be 85,222,29,68,33,234,179,103,37,68.
I was able to swap first element (68) with the last element (85), but numbers 222,29,and 68 have changed to 44,37,and 100. What changes do I need to make with the codes in swap_byte_first_last? Other parts of the code were given.

Printing array as double word in assembly

%include "asm_io.inc"
;
; initialized data is put in the .data segment
;
segment .data
array: dd 180,32,455,499,388,480,239,346,257,84
fmt: dd ",%d",0
; uninitialized data is put in the .bss segment
;
segment .bss
resd 10
;
; code is put in the .text segment
;
segment .text
extern printf
global asm_main
asm_main:
enter 0,0 ; setup routine
pusha
; The following is just example of how to print an array
push dword 10
push dword array
call print_array
add esp,8 ; clean up stack
; don't delete anything following this comment
popa
mov eax, 0 ; return back to C
leave
ret
segment .data
ListFormat db ",%u", 0
segment .text
global print_array
print_array:
enter 0,0
push esi
push ebx
xor esi, esi ; esi = 0
mov ecx, [ebp+12] ; ecx = n
mov ebx, [ebp+8]
xor edx, edx
mov dl, [ebx + esi] ; ebx = address of array
mov eax,edx
call print_int
dec ecx
inc esi
print_loop:
xor edx,edx
mov dl,[ebx + esi]
push ecx ; printf might change ecx!
push edx ; push array value
push dword ListFormat
call printf
add esp, 8 ; remove parameters (leave ecx!)
inc esi
pop ecx
loop print_loop
call print_nl
pop ebx
pop esi
leave
ret
So this code prints out 180,0,0,0,32,0,0,0,199,1 when I want to print out 180,32,455,499,388,480,239,346,257,84. I think that it's because this is designed to print byte words. I'm trying to print in double words and I'm guessing something in the print_array needs to be changed. I tried mov dl, [ebx+esi*4] but it still doesn't print the array that I want to print. Or does something else needs to be changed to print array of double words?
You could leave it at changing the mov dl, [ebx+esi] instruction into mov edx, [ebx+esi*4], but that would be just half the fun!
1 Why not try to make a loop that can deal with the special case of the first value in the list that doesn't need the comma prefix? No more using print_int.
2 Also don't use the LOOP instruction. It's slow! The pair cmp jb (that can macro-fuse) is much better.
3 And replacing the prolog enter 0,0 and epilog leave codes by simply addressing the parameters via ESP relative addressing is simple enough.
4 Always consider the special cases! What if the array happens to be empty?
print_array:
push ebx
push esi
mov ebx, [esp+12] ; Begin array
mov esi, [esp+16] ; n
test esi, esi
jz done
lea esi, [ebx+esi*4] ; End array
mov edx, ListFormat+1 ; "%u"
more: mov eax, [ebx] ; Array dword value
push eax
push edx ; "%u" first time, ",%u" others
call printf
add esp, 8
add ebx, 4 ; To next dword in the array
mov edx, ListFormat ; ",%u"
cmp ebx, esi ; Current address < Last address ?
jb more ; Yes
call print_nl
done: pop esi
pop ebx
ret
Under the right conditions, keeping ESP fixed inside this loop can be worth doing. See Peter Cordes' comments below this answer.
Next is a version of this code that keeps ESP fixed inside the loop:
print_array:
push ebx
push esi
mov ebx, [esp+12] ; Begin array
mov esi, [esp+16] ; n
test esi, esi
jz done
sub esp, 8 ; Space for the printf args
lea esi, [ebx+esi*4] ; End array
mov edx, ListFormat+1 ; "%u"
more: mov eax, [ebx] ; Array dword value
mov [esp+4], eax
mov [esp], edx ; "%u" first time, ",%u" others
call printf
add ebx, 4 ; To next dword in the array
mov edx, ListFormat ; ",%u"
cmp ebx, esi ; Current address < Last address ?
jb more ; Yes
call print_nl
add esp, 8
done: pop esi
pop ebx
ret

X86 Assembly Printing Max in Array returns Segmentation fault (core dumped)

My program works, but there is something wrong with my printMax function. The program terminates with a
Segmentation fault (core dumped).
I have tried building a stack for the function and just doing a pusha popa and both ways, I get the seg fault core dumped.
I've tried calling the function, but it just runs twice.
Any idea what I am doing wrong?
SECTION .data ;data section
msg1 : db "Here are the array elements:", 10, 0
msg1Len: equ $-msg1
msg2 : db "Here is the max value in the array:", 10, 0
msg2Len: equ $-msg2
arr : dd 2,4,6,8,10,20,40
arrLen : equ ($-arr)/4 ;number of elements = array length / 4
SECTION .bss
max resd 1 ;declare and reserve space for max
SECTION .text
global main
main:
push ebp
mov ebp, esp
mov ecx, msg1 ;print msg1
mov edx, msg1Len
call PString
;save array base address in ebx and save sizein in ecx
mov ebx, arr
mov ecx, arrLen; store num elements in ecx
;loop to print array
PrintArray:
mov eax, [ebx] ;move value [ebx] to eax
call PrintDec
call Println
add ebx, 4
loop PrintArray
printMax:
section .text
pusha
;reset array to find max
mov ebx, arr
mov ecx, arrLen
loopForMax:
mov eax, [ebx]
cmp eax, [ebx +4]
jle sameMax
mov [max], eax
sameMax:
add ebx, 4 ;move to next element
loop loopForMax
mov ecx, msg2
mov edx, msg2Len
call PString
mov eax, [max]
call PrintDec
call Println
popa
ret
;exit program and clean stack
mov esp, ebp
pop ebp
ret
PString:; save register values of the called function
pusha
mov eax,4 ; use 'write' system call = 4
mov ebx,1 ; file descriptor 1 = STDOUT
int 80h ; call the kernel
; restore the old register values of the called function
popa
ret
Println:
;will call PString func
;will change content of ecx and edx
;need to save registers used by the main program
section .data
nl db 10
section .text
pusha
mov ecx, nl
mov edx, 1
call PString
;return original register values
popa
ret
PrintDec:
;saves all registers so they return unmodified
;build the function to handle dword size
section .bss
decstr resb 10 ; 10 32-bit digits
ct1 resd 1 ;keep track of dec-string size
section .text
pusha; save registers
mov dword[ct1],0 ;initially assume 0
mov edi, decstr ; edi points to dec-string
add edi, 9 ; moved to the last element of string
xor edx, edx ; clear edx for 64-bit div
whileNotZero:
mov ebx, 10 ; get ready to divide by 10
div ebx ; divide by 10
add edx, '0' ; convert to ascii
mov byte[edi], dl ; put it in string
dec edi ; move to next char in str
inc dword[ct1] ; inc char counter
xor edx, edx ; clear edx
cmp eax, 0 ;is remainder 0?
jne whileNotZero ;if no, keep on looping
inc edi ; conversion finished, bring edi
mov ecx, edi ; back to start of string. make ecx
mov edx, [ct1] ; point to counterm edx gets # chars
mov eax, 4 ; print to stdout
mov ebx, 1
int 0x80 ; call kernel
popa ; restore registers
ret

NASM programming - Segmentation fault(core dumped)

My program is very simple. It takes two input from the user:
an array (only 2 digit positive numbers)
a 2-digit number to be searched
output: number of times the given no. occurs in array
sample
Enter the size of array
03
Enter a number
10
Enter a number
12
Enter a number
10
Enter the number to be searched
10
Your number appeared 02 times
everything seems to be working fine but this programs gives the error
0segmentation fault(core dumped)
Please help me solve this problem
enter code here
section .data
msg1: db "Enter the size of array",10
len1: equ $-msg1
msg2: db "Enter a number",10
len2: equ $-msg2
msg3: db "Enter the number to be searched :"
len3: equ $-msg3
msg4: db "Your entered number appeared "
len4: equ $-msg4
section .bss
temp: resb 1
array: resb 100
d1: resb 1
d0: resb 1
size: resb 1
num: resb 1
ele: resb 1
time: resb 1
section .text
global _start:
_start:
;Getting the size of array
mov eax,4
mov ebx,1
mov ecx,msg1
mov edx,len1
int 80h
mov eax,3
mov ebx,0
mov ecx,d1
mov edx,1
int 80h
mov eax,3
mov ebx,0
mov ecx,d0
mov edx,2
int 80h
sub byte[d1],48
sub byte[d0],48
mov al,byte[d1]
mov bl,10
mul bl
add byte[d0],al
mov al,byte[d0]
mov byte[size],al
mov byte[temp],al
mov ebx,array
reading:
push rbx ;preserves the value of ebx
mov eax,4
mov ebx,1
mov ecx,msg2
mov edx,len2
int 80h
mov eax,3
mov ebx,0
mov ecx,d1
mov edx,1
int 80h
mov eax,3
mov ebx,0
mov ecx,d0
mov edx,2
int 80h
sub byte[d1],48
sub byte[d0],48
mov al,byte[d1]
mov bl,10
mul bl
add byte[d0],al
mov al,byte[d0]
pop rbx
mov byte[ebx],al
add ebx,1
dec byte[temp]
cmp byte[temp],0
jg reading
mov eax,4
mov ebx,1
mov ecx,msg3
mov edx,len3
int 80h
mov eax,3
mov ebx,0
mov ecx,d1
mov edx,1
int 80h
mov eax,3
mov ebx,0
mov ecx,d0
mov edx,2
int 80h
sub byte[d1],48
sub byte[d0],48
mov al,byte[d1]
mov bl,10
mul bl
add byte[d0],al
mov al,byte[d0]
mov byte[ele],al
mov cl,byte[size]
mov byte[temp],cl
mov byte[time],0
search:
mov al,byte[ebx]
cmp byte[ele],al
jne nf
jmp f
mov cl,0
f: add ebx,1
add byte[time],1
dec byte[temp]
cmp byte[temp],cl
jg search
jmp next
nf:
add ebx,1
add byte[time],0
dec byte[temp]
cmp byte[temp],cl
jg sea rch
jmp next
next:
mov eax,4
mov ebx,1
mov ecx,msg4
mov edx,len4
int 80h
movzx ax,byte[time]
mov bl,10
div bl
mov byte[d1],al
mov byte[d0],ah
add byte[d0],48
add byte[d1],48
mov eax,4
mov ebx,1
mov ecx,d1
mov edx,1
int 80h
mov eax,4
mov ebx,1
mov ecx,d0
mov edx,1``
int 80h
mov eax,1
mov ebx,0
int 80h
global _start
section .text
_start:
mov rax,1
mov rdi,1
mov rsi,msg
mov rdx,msglen
syscall
mov rax,0
mov rdi,0
mov rsi,no1
mov rdx,5
syscall
mov rax,1
mov rdi,1
mov rsi,msg1
mov rdx,msg1len
syscall
mov rax,0
mov rdi,0
mov rsi,no2
mov rdx,5
syscall
mov rax,[no1]
sub rax,30h
mov rbx,[no2]
sub rbx,30h
add rax,rbx
add rax,30h
mov [res],rax
mov rdx,2
syscall
mov rax,1
mov rdi,1
mov rsi,res
mov rdx,2
syscall
mov rax,60h
mov rdx,0
syscall
section .data
msg: db "Enter 1st Number",0x0a
msglen equ $ -msg
msg1: db "Enter 2st Number",0x0a
msg1len equ $ -msg1
msg2:db "Addition is==",0x0a
msg2len equ $ -msg2
section .bss
no1: resb 5
no2: resb 5
res: resb 15
Looking at the source, I noticed one thing. I think your 'search' loop goes out of bounds because you failed to initialize register cl; the instruction mov cl,0 is currently dead code; it is beneath an unconditional jump so it never ever gets executed.
But as I said earlier, when in doubt, use a debugger.

Resources