1. Limited time only! Sign up for a free 30min personal tutor trial with Chegg Tutors
    Dismiss Notice
Dismiss Notice
Join Physics Forums Today!
The friendliest, high quality science and math community on the planet! Everyone who loves science is here!

[nasm] Simple Array Reading Program

  1. Nov 4, 2012 #1
    1. The problem statement, all variables and given/known data

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


    3. 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 (Text):


    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: Nov 5, 2012
  2. jcsd
  3. Nov 5, 2012 #2

    Mark44

    Staff: Mentor

    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.
     
  4. Nov 5, 2012 #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 (Text):
    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?
     
  5. Nov 5, 2012 #4

    Mark44

    Staff: Mentor

    I believe so.
    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.
    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.
     
  6. Nov 5, 2012 #5

    rcgldr

    User Avatar
    Homework Helper

    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 (Text):

    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 (Text):

            mov     eax, esi
            add     eax, 30h
            mov     esi, eax
     
    to this:

    Code (Text):

            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: Nov 5, 2012
  7. Nov 5, 2012 #6
    I can't figure out what's going on.

    Code (Text):

    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 (Text):

    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.
     
  8. Nov 5, 2012 #7

    Mark44

    Staff: Mentor

    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.
     
  9. Nov 6, 2012 #8

    rcgldr

    User Avatar
    Homework Helper

    Code (Text):

            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 (Text):

            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: Nov 6, 2012
Know someone interested in this topic? Share this thread via Reddit, Google+, Twitter, or Facebook




Similar Discussions: [nasm] Simple Array Reading Program
Loading...