[nasm] Simple Array Reading Program

In summary: I'll make the necessary changes and run it through the debugger again to see if it works properly now. Thanks for your help!
  • #1
twoski
181
2

Homework Statement



Write a program in nasm which will read through a 5x5 matrix and print the largest value.

The Attempt at a Solution



I ran this through a debugger and for some reason $edi reaches 19 and sets $esi to 0. Which is weird since the value at [eax + edi * 4] should be 4, not 0.

My output code is wonky too, i could use some help with that.

Code:
segment .data

    matrix dd 1,1,1,1,1, \
              2,2,2,2,2, \
              3,3,3,3,3, \
              4,4,4,4,4, \
              5,5,5,5,5

segment .bss

    empty resb 4
    count resb 4

segment .text

    global _start

_start:

    mov eax, matrix
    call FindGreatest
	
FindGreatest:

    mov esi, [empty] 
    mov edi, [count] 
    mov edi, 0
    jmp Switch

Comparison:

    inc edi 
    cmp esi, [eax + edi * 4] ; compare stored number with new number
    jg Switch ; it's bigger so replace it
    cmp edi, 25 ; check if we are out of bounds
    jle Comparison ; start over again if we can
    mov eax, esi
	add eax, 30h ; is this the proper way to convert?
    mov esi, eax
    jmp Print ; print the value now that we have traversed the matrix             

Switch:

    mov esi, [eax + edi * 4] ; we found a higher number
    jmp Comparison
	
Print:

    mov edx, 4
    mov ecx, esi ; we are outputting the stored digit as text 
    mov	ebx, 1	
    mov	eax, 4 ; output with stdio
    int	0x80
    jmp exit

exit:

    mov eax, 1
    xor ebx, ebx
    int 0x80
 
Last edited:
Physics news on Phys.org
  • #2
twoski said:

Homework Statement



Write a program in nasm which will read through a 5x5 matrix and print the largest value.


The Attempt at a Solution



I ran this through a debugger and for some reason $edi reaches 19 and sets $esi to 0. Which is weird since the value at [eax + edi * 4] should be 4, not 0.

My output code is wonky too, i could use some help with that.

Code:
segment .data

    matrix dd 1,1,1,1,1, \
              2,2,2,2,2, \
              3,3,3,3,3, \
              4,4,4,4,4, \
              5,5,5,5,5

segment .bss

    empty resb 4
    count resb 4

segment .text

    global _start

_start:

    mov eax, matrix
    call FindGreatest
	
FindGreatest:

    mov esi, [empty] 
    mov edi, [count] 
    mov edi, 0
    jmp Switch

Comparison:

    inc edi 
    cmp esi, [eax + edi * 4] ; compare stored number with new number
    jg Switch ; it's bigger so replace it
    cmp edi, 25 ; check if we are out of bounds
    jle Comparison ; start over again if we can
    mov eax, esi
	add eax, 30h ; is this the proper way to convert?
    mov esi, eax
    jmp Print ; print the value now that we have traversed the matrix             

Switch:

    mov esi, [eax + edi * 4] ; we found a higher number
    jmp Comparison
	
Print:

    mov edx, 4
    mov ecx, esi ; we are outputting the stored digit as text 
    mov	ebx, 1	
    mov	eax, 4 ; output with stdio
    int	0x80
    jmp exit

exit:

    mov eax, 1
    xor ebx, ebx
    int 0x80

You have a couple of things that seem weird to me, that might be causing problems for you. First, your count label isn't initialized at the start. When your code starts, you move the first matrix value into eax, and then call FindGreatest. You then move the address of empty to esi and the address of count into edi. You then overwrite edi with 0, so what was the point of the previous instruction?

Second, why do you call FindGreatest? If you deleted the line with "call FindGreatest" you code would behave exactly the same.

Third, the last instruction in FindGreatest branches to Switch. This causes the value that was in esi (the address of empty) to be overwritten by a new value. The comment here is misleading, since it says you have found a larger number.

Fourth, you have a variable named count that you never use. Instead you have hard-coded 25 (the count of elements in matrix) in the Comparison section.

The good news is that you are using a debugger, which is an important tool when you are writing assembly code. A useful exercise for you is to hand-simulate what you think your code is doing for two or three iterations, and then use your debugger to verify that your predictions were correct.
 
  • #3
Thanks for your reply! I'm noticing a lot of silly errors now, i guess it's good to get a good night's sleep then re-read your code.

I think my program can work fine without the two variables i am using. 'count' isn't needed, nor is 'empty'.

I did some tidying up, my output code is still wonky at best. Is "mov ecx esi" a valid instruction?

Code:
mov eax, esi
add eax, 30h 
mov esi, eax
jmp Print

Is this the correct way to convert decimal to a printable character? And would it work for numbers with >1 digit?
 
  • #4
twoski said:
Thanks for your reply! I'm noticing a lot of silly errors now, i guess it's good to get a good night's sleep then re-read your code.

I think my program can work fine without the two variables i am using. 'count' isn't needed, nor is 'empty'.

I did some tidying up, my output code is still wonky at best. Is "mov ecx esi" a valid instruction?
I believe so.
twoski said:
Code:
mov eax, esi
add eax, 30h 
mov esi, eax
jmp Print

Is this the correct way to convert decimal to a printable character?
This is the correct way to convert a single decimal digit to the corresponding digit character. For example, if 4 is copied to eax from esi, the next instruction adds 30h, resulting in 34h or 5210. This is the ASCII code for the '4' character.
twoski said:
And would it work for numbers with >1 digit?
No, it works only with single-digit number.

Your Print routine uses interrupt 0x80, which suggests to me that your OS is Linux, since that's not a DOS interrupt function. I don't know what functions are available with this interrupt, so you're on your own there. If you want to print 35, for example, you will need a loop that figures out what digit is in the 10's place and what digit is in the 1's place, and then display each digit as a character.
 
  • #5
twoski said:
Is "mov ecx esi" a valid instruction?
Yes, but it would be "mov ecx, esi".

Some optional changes you could make to the code:

You can use this to define an equate for the number of entries in matrix:

Code:
matrix  dd    1,1,1,1,1, \
              2,2,2,2,2, \
              3,3,3,3,3, \
              4,4,4,4,4, \
              5,5,5,5,5
matrixlen equ ($-matrix) / 4

X86 allows any register to be used as an operand with most instructions, so you can change this:

Code:
        mov     eax, esi
        add     eax, 30h 
        mov     esi, eax

to this:

Code:
        add     esi, 30h

Although X86 allows eax (32 bit mode) and rax (64 bit mode) to be used as a pointer, some instructions only allow eax or part of eax to be used as an operand (LODS..., SCAS..., STOS..., MUL, DIV, XLAT, ...), so generally it's not used as a pointer. Other instructions also use specific registers, MUL and DIV use eax + edx. INPS... and OUTS... use edx as the port pointer. The string instructions use esi for source pointer, edi for destination pointer (except SCAS... uses edi as the pointer). Loop instructions use ecx. XLAT uses ebx for source pointer. PUSH... and POP... use esp for the stack pointer. Using ebp as a pointer defaults to using the stack segment (SS). Typically, ebx, esi, and edi are the most common registers to use as pointers to main memory, and ebp as a pointer for stack based variables or function parameters (since it defaults to stack segment).
 
Last edited:
  • #6
I can't figure out what's going on.

Code:
segment .data

    MATRIXLEN equ 25

    matrix dd 1,2,1,1,1, \
              2,2,2,2,2, \
              3,3,3,3,3, \
              4,4,4,4,4, \
              5,5,5,5,5

segment .bss

segment .text

    global _start

_start:

    mov eax, matrix
	
FindGreatest:

    mov edi, 0
    jmp Switch

Comparison:

    inc edi 
    cmp esi, [eax + edi * 4] 
    jg Switch 
    cmp edi, MATRIXLEN
    jle Comparison 
    add esi, 30h 
    jmp Print

Switch:

    mov esi, [eax + edi * 4]
    jmp Comparison
	
Print:

    mov edx, 4
    mov ecx, esi  
    mov	ebx, 1	
    mov	eax, 4 ; output with stdio
    int	0x80

exit:

    mov eax, 1
    xor ebx, ebx
    int 0x80

In the debugger, the code starts properly. But:

Code:
cmp esi, [eax + edi * 4] 
    jg Switch

This line doesn't work it seems. No matter what the value for $edi is, it doesn't jump to Switch when it should. For example, if $esi is 1 and $edi is 6, it should be jumping to Switch since [eax + edi * 4] is greater than 1.
 
  • #7
That's not the way cmp works.

cmp A, B does a subtraction of A - B. Since 1 - (eax + 6*4) is apparently negative (I don't know the value of eax), the jg instruction doesn't execute. jl would, though.

I'm a little rusty on this, but I believe that if A < B, SF (sign flag) in the flags register gets set. If the two values happen to be equal, ZF (zero flag) gets set. The conditional jump instructions use the flags register to determine whether the jump should be taken.
 
  • #8
twoski said:
I can't figure out what's going on.

Code:
        cmp     esi, [eax + edi * 4] 
        jg      Switch

cmp works similar to subtract: the comparson is based on esi - [eax + edi*4] . You want to branch when esi is less than the matrix value (which means the matrix value is > esi), so what you want here is:

Code:
        cmp     esi, [eax + edi * 4] 
        jl      Switch

If these were unsigned numbers then you would use jb Switch instead (jump if borrow set).

Also look at my previous post for an alternate way to define matrixlen so that it's based on the actual size of matrix.
 
Last edited:

Related to [nasm] Simple Array Reading Program

1) What is a simple array reading program in NASM?

A simple array reading program in NASM is a program written in the assembly language NASM that allows the user to input values into an array and then read and manipulate those values.

2) How does a simple array reading program work?

A simple array reading program works by first declaring an array and its size, then using a loop to prompt the user for input and store the input in the array. The program can then use another loop to read and manipulate the values in the array.

3) What are the benefits of using a simple array reading program?

Using a simple array reading program can help with data organization and manipulation, as well as improve efficiency in certain tasks. It can also help with understanding how the computer stores and accesses data.

4) Are there any limitations to using a simple array reading program?

One limitation of using a simple array reading program is that it may not be suitable for large amounts of data or complex data structures. Additionally, it may require a basic understanding of assembly language and computer architecture.

5) Can a simple array reading program be used in other programming languages?

Yes, the concept of a simple array reading program can be applied to other programming languages, as arrays are a fundamental data structure. However, the specific implementation may vary depending on the language.

Similar threads

  • Engineering and Comp Sci Homework Help
Replies
1
Views
2K
  • Engineering and Comp Sci Homework Help
Replies
4
Views
2K
Back
Top