Author Topic: Reading a NASM Matrix, not displaying the right information  (Read 12370 times)

Offline RaenirS

  • Jr. Member
  • *
  • Posts: 8
Reading a NASM Matrix, not displaying the right information
« on: March 26, 2013, 04:31:02 AM »
Below is my code based on some code snippets I found online that I tried to cudgle together. The result of 1234 into the 2 v 2 matrix is for the largest number to be 3, while the result of 4321 is accurately 4; with some weirdness if I use other numbers.

Seems like to me that its only finding the largest number of the first row, and not the other rows.

Also the anti spam picture game is kinda obnixious the first 50 times... Does it ever go away?

Code: [Select]
segment .bss
  num: resw 1 ;For storing a number, to be read of printed....
  nod: resb 1 ;For storing the number of digits....
  temp: resb 2
  matrix1: resw 200
  m: resw 1
  n: resw 1
  i: resw 1
  j: resw 1
buff resb 4
 
segment .data
  msg1: db "Enter the number of rows in the matrix : "
  msg_size1: equ $-msg1
  msg2:  db "Enter the elements one by one(row by row) : "
  msg_size2: equ $-msg2
  msg3: db "Enter the number of columns in the matrix : "
  msg_size3: equ $-msg3
  tab: db  9 ;ASCII for vertical tab
  new_line: db 10 ;ASCII for new line
 

segment .text

global _start

_start:
  mov eax, 4
  mov ebx, 1
  mov ecx, msg1
  mov edx, msg_size1
  int 80h
 
  mov ecx, 0
  call read_num 
  mov cx, word[num]
  mov word[m], cx
 
 
  mov eax, 4
  mov ebx, 1
  mov ecx, msg3
  mov edx, msg_size3
  int 80h
 
  mov ecx, 0
  call read_num 
  mov cx, word[num]
  mov word[n], cx
 
 
 
  mov eax, 4
  mov ebx, 1
  mov ecx, msg2
  mov edx, msg_size2
  int 80h
 
 
  ;Reading each element of the matrix........
  mov eax, 0
  mov ebx, matrix1 
 
  mov word[i], 0
  mov word[j], 0
 
 
  i_loop:
    mov word[j], 0
    j_loop:
 
 call read_num
mov dx , word[num]
 ;eax will contain the array index and each element is 2 bytes(1 word) long
 mov  word[ebx + 2 * eax], dx
 inc eax    ;Incrementing array index by one....
     
 
 
 inc word[j]
 mov cx, word[j]
 cmp cx, word[n]
 jb j_loop
 
    inc word[i]
    mov cx, word[i]
    cmp cx, word[m]
    jb i_loop
; read out matrix code
xor     esp, [matrix1]         ; esp initialized to first element in array, & is first largest value
;xor     edi, edi          ; edi initialized to 0, edi is loop counter
  ;Pretty sure this is the "read" matrix code.
    ;Reading each element of the matrix.(Storing the elements in row major order).......
  mov ebp, 0
  mov edi, matrix1 
 
  mov word[i], 0
  mov word[j], 0
 
 
  i_loop2:
    mov word[j], 0
    j_loop2:
 
   ;eax will contain the array index and each element is 2 bytes(1 word) long
   mov  dx, word[edi+2*ebp]   ;
   mov word[num] , dx
   ;call print_num ; stub
   ;cmp esp, [edi+2*ebp] ;word[ebx + 2 * eax] ; compares current biggest number with current element iterated.
;;;; #### I think this is my debug mode code.... ;;;;
    mov eax, 4 ;
    mov ebx, 1
    mov ecx, [edi+2*ebp]
    add ecx, 48
    mov [buff], ecx
    mov ecx, buff
    mov edx, 4
       int 80h
   
 cmp esp, [edi+2*ebp] ;word[ebx + 2 * eax] ; compares current biggest number with current element iterated.
   jge   skip
   mov esp, [edi+2*ebp] ;word[ebx + 2 * eax] ; stores new biggest number
   mov esi, ebp ; Stores pointer to the biggest element   
 
 
 
   skip:
inc ebp
 inc word[j]
 mov cx, word[j]
 cmp cx, word[n]
 jb j_loop2

    inc word[i]
    mov cx, word[i]
    cmp cx, word[m]
    jb i_loop2

;;matrix hack exit code ... //
;loop:

;cmp   edi, 25           ; Make sure the end of the matrix has not been reached // set to 25
;jge   end_loop          ; If the end has been reached, jump out of the loop

             ; If it's not greater than the current max, skip it

 

;    mov eax, 4 ;
;    mov ebx, 1
;    mov ecx, [matrix+edi*4]
;    add ecx, 48
;    mov [buff], ecx
;    mov ecx, buff
;    mov edx, 4
; int 80h


;add   edi, 1            ; increment the counter
;jmp     loop              ; Loop to the end of the matrix

;end_loop:

; outut
    mov eax, 4 ; system_write
    mov ebx, 1  ; stdout
    mov ecx, [edi+2*esi] ; move biggest element to accumulator
    add ecx, 30h ; convert to ascii representation
    mov [buff], ecx ; move to memory
    mov ecx, buff ; put pointer in ecx for printing
    mov edx, 4 ; size, 4 bytes
int 80h ; sytem call.


exit:
  mov eax, 1
  mov ebx, 0
  int 80h
 
;Function to read a number from console and to store that in num
read_num:

  pusha
  mov word[num], 0
 
  loop_read:
    mov eax, 3
    mov ebx, 0
    mov ecx, temp
    mov edx, 1
    int 80h
   
    cmp byte[temp], 10
      je end_read
   
    mov ax, word[num]
    mov bx, 10
    mul bx
    mov bl, byte[temp]
    sub bl, 30h
    mov bh, 0
    add ax, bx
    mov word[num], ax
    jmp loop_read
  end_read:
  popa
 
ret

« Last Edit: March 26, 2013, 04:34:19 AM by RaenirS »

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Reading a NASM Matrix, not displaying the right information
« Reply #1 on: March 26, 2013, 09:15:21 AM »
I get really confused around here...
Code: [Select]
; read out matrix code
xor     esp, [matrix1]         ; esp initialized to first element in array, & is first largest value

In the first place, esp is your stack pointer and it's generally not a good idea to put a random value in it. In the second place, it's too big a register - you made the numbers words, remember? Using a 32-bit register is going to get (and compare) two of them. Moving a 32-bit register into your matrix is worse. In the third place, "xor"? Doesn't match what you say in the comment...

You seem to be on the right track. I think if you clear up a few instances of 16/32-bit confusion you'll have it. (it might be easier to use dwords throughout, but your "read_num" is for words...)

I apologize for the guess-the-picture games. I think it goes away after a while. Blame the spammers.

Best,
Frank


Offline RaenirS

  • Jr. Member
  • *
  • Posts: 8
Re: Reading a NASM Matrix, not displaying the right information
« Reply #2 on: March 26, 2013, 09:39:34 AM »
ESP is the stack pointer as in what it is officially supposed to do/intended? I was running out of registers so I didn't really have a choice. The thing about 16/32 bit has a bit of a problem of where its really difficult to actually output what they contain, the output code template seems to only work with 32 bit registers and the conversion I didn't know what to do, and seemed to largely work; so I didn't want to mess with what wasn't broke.

XOR as I understand it, is an exclusive or that will set the value to a something, if its xor ecx, ecx it "zeroes" out the register the same way as mov ecx, 0 I believe; and does seem to work to point to the first element in the matrix....

I managed to "solve" the problem after a while from switch from the logic which was using the counter pointer of trying to track WHERE the largest number was, to simply storing the largest number as the user inputs it; because the logic seemed to be stuck to the first row and I couldn't get it to unstuck it.

Code: [Select]
segment .bss
  num: resw 1 ;For storing a number, to be read of printed....
  nod: resb 1 ;For storing the number of digits....
  temp: resb 2
  matrix1: resw 200
  m: resw 1
  n: resw 1
  i: resw 1
  j: resw 1
buff resb 4
 
segment .data
  msg1: db "Enter the number of rows in the matrix : "
  msg_size1: equ $-msg1
  msg2:  db "Enter the elements one by one(row by row) : "
  msg_size2: equ $-msg2
  msg3: db "Enter the number of columns in the matrix : "
  msg_size3: equ $-msg3
 msg4: db "The Largest Number is... : "
  msg_size4: equ $-msg4

  tab: db  9 ;ASCII for vertical tab
  new_line: db 10 ;ASCII for new line

segment .text

global _start

_start:
  mov eax, 4
  mov ebx, 1
  mov ecx, msg1
  mov edx, msg_size1
  int 80h
 
  mov ecx, 0
  call read_num 
  mov cx, word[num]
  mov word[m], cx
 
 
  mov eax, 4
  mov ebx, 1
  mov ecx, msg3
  mov edx, msg_size3
  int 80h
 
  mov ecx, 0
  call read_num 
  mov cx, word[num]
  mov word[n], cx
 
 
 
  mov eax, 4
  mov ebx, 1
  mov ecx, msg2
  mov edx, msg_size2
  int 80h
 
 
  ;Reading each element of the matrix........
  mov eax, 0
  mov ebx, matrix1 
 
  mov word[i], 0
  mov word[j], 0
 
 
  i_loop:
    mov word[j], 0
    j_loop:
 
 call read_num
mov dx , word[num]
 ;eax will contain the array index and each element is 2 bytes(1 word) long
 mov  word[ebx + 2 * eax], dx
 

 
 inc eax    ;Incrementing array index by one....
     
 
 
 inc word[j]
 mov cx, word[j]
 cmp cx, word[n]
 jb j_loop
 
    inc word[i]
    mov cx, word[i]
    cmp cx, word[m]
    jb i_loop
; read out matrix code
xor     esp, [matrix1]         ; esp initialized to first element in array, & is first largest value
;xor     edi, edi          ; edi initialized to 0, edi is loop counter


  ;Loop through the matrix, check each number if its larger than the first number in the array. AT the end print said number.
 
    ;Reading each element of the matrix.(Storing the elements in row major order).......
  mov ebp, 0
  mov edi, matrix1 
  mov esp, 0
 
  mov word[i], 0
  mov word[j], 0
 
 
  i_loop2:
    mov word[j], 0
    j_loop2:
 
   ;eax will contain the array index and each element is 2 bytes(1 word) long
   mov  dx, word[edi+2*ebp]   ;
   mov word[num] , dx



    cmp esp, [num] ;word[ebx + 2 * eax] ; compares current biggest number with current element iterated.
    jge   skip
    mov esp, [num] ;word[ebx + 2 * eax] ; stores new biggest number
    mov esi, ebp                ; Stores pointer to the biggest element



    skip:
;debug code
    ;mov eax, 4 ;
    ;mov ebx, 1
    ;mov ecx, esp
    ;add ecx, 48
    ;mov [buff], ecx
    ;mov ecx, buff
    ;mov edx, 4
    ;int 80h
   ;mov esp, [num]
   
inc ebp
 inc word[j]
 mov cx, word[j]
 cmp cx, word[n]
 jb j_loop2

    inc word[i]
    mov cx, word[i]
    cmp cx, word[m]
    jb i_loop2

;outut
  mov eax, 4
  mov ebx, 1
  mov ecx, msg4
  mov edx, msg_size4
  int 80h
mov ecx, 0

    mov eax, 4 ; system_write
    mov ebx, 1  ; stdout
    mov ecx, esp ; move biggest element to accumulator
    add ecx, 48 ; convert to ascii representation
    mov [buff], ecx ; move to memory
    mov ecx, buff
    mov edx, 4 ; size, 4 bytes
    int 80h

exit:
  mov eax, 1
  mov ebx, 0
  int 80h
 
;Function to read a number from console and to store that in num
read_num:

  pusha
  mov word[num], 0
 
  loop_read:
    mov eax, 3
    mov ebx, 0
    mov ecx, temp
    mov edx, 1
    int 80h
   
    cmp byte[temp], 10
      je end_read
   
    mov ax, word[num]
    mov bx, 10
    mul bx
    mov bl, byte[temp]
    sub bl, 30h
    mov bh, 0
    add ax, bx
    mov word[num], ax

    jmp loop_read
  end_read:
  popa
 
ret



Here's the working code. Ideally I would want it to output based on the position of counter but that only seems to work with a 1 dimensional array, I have no idea how to specify a location in a 2 dimensional array in nasm land.

Offline RaenirS

  • Jr. Member
  • *
  • Posts: 8
Re: Reading a NASM Matrix, not displaying the right information
« Reply #3 on: March 26, 2013, 09:59:54 AM »
I looked at it again considering my new information and here is what I cannot understand:

the "outer" loop is controlled by cx, which increments by 1.
dx is the value carried at matrix @ position eax (controlled in the inner loop, surprisingly not by ax or whatever the inner loop counter is...?)

SOMEHOW word[edi+2*ebp] (or word[ebx+2*eax] ) KNOWS which row it is at based on cx, how is beyond me as they are never directly refernece afaik, I am likely missing something.

Meaning, if I knew how they were related, then I would need two things, to save the value of "eax/ebp" whichever counter I used for the column index counter, AND the value of the row counter (cx) and then somehow manage to trick through vile magick of which mankind is not meant to know to spit out the number at that location.

Would I, assuming this use:

Code: [Select]
; outut
    mov eax, 4 ; system_write
    mov ebx, 1  ; stdout
    mov dh, cx ; move row index
    mov ecx, [edi+2*esi] ; move biggest element to accumulator
    ; since esi is the reference to WHERE which column on a given row the biggest number is, assuming
    ; moving cx "triggers" it to look there, will this be position matrix[dh][esi]?
    add ecx, 30h ; convert to ascii representation
    mov [buff], ecx ; move to memory
    mov ecx, buff ; put pointer in ecx for printing
    mov edx, 4 ; size, 4 bytes
int 80h ; sytem call.

Offline TightCoderEx

  • Full Member
  • **
  • Posts: 103
Re: Reading a NASM Matrix, not displaying the right information
« Reply #4 on: March 26, 2013, 02:52:03 PM »
ESP is the stack pointer as in what it is officially supposed to do/intended? I was running out of registers so I didn't really have a choice.

When your background is a higher level language such as C, C++ or Basic even, you are shielded from the intricacies of the processor. Code and logic therefore are more abstract in nature than coding at this level (assembly). When you understand the intent and purpose of each of the registers, you will soon see how your logic using ESP is flawed. As a matter of fact, that is that pointers intent and purpose to extend temporarily the amount of registers you have if you will.

Even in 64 bit now, I still have to remind myself that there are 8 more I can use (R15-R08).
 
Ideally I would want it to output based on the position of counter but that only seems to work with a 1 dimensional array, I have no idea how to specify a location in a 2 dimensional array in nasm land.

At this level, there is no such thing as an array.  Consider this snippet.

Code: [Select]

    ; read_num procedure returns integer value in EAX

        call    read_num        ; Get number of rows, multiplyer
        mov     ecx, eax
        call    read_num        ; Get number of columns, multiplicand

        xor     edx, edx        ; Needs to be null

        imul    ecx
        shl     eax, 1          ; EAX *= 2 (words)
        sub     esp, eax        ; Make room on stack for array
        mov     ebp, esp        ; EBP becomes pointer to that array

        push    ecx             ; Save number of rows @ [EBP-4]
                                                                                               

All the app cares about is how much memory, therefore let's consider 9 rows and 24 columns / row.  This gives us 216 elements and because we're saving 16 bit values, we need 432 bytes of memory. Then after the stack pointer is adjusted to the appropriate amount of space, the number of rows are saved and is now pointed to by [EBP-4] in this example.

Whenever you want to know what row and column your in, it's simply (CUR_POINTER - BASE_POINTER) / ROWS.  Result EAX=Row & EDX=Column

Code: [Select]

        mov     ecx, [ebp-4]
        mov     eax, Pointer
        sub     eax, ebp
        div     ecx                                                           


The essential points I'd like to make here is, first and foremost, get a really good understanding of the instruction set and architecture. Without those two, you're going to struggle unnecessarily at this level. Secondly, format you code with ample comments with entry points tabulated as a lot of code can be written in a short time and it is easy to lose track of where you are.  This is just a small snippet from a boot-loader of mine

Code: [Select]

        ; Move postamble out of way as it will probably get overwritten for metrics
        ; that have max sectors of 63

       .MovBlk  mov     si, A20
                call    ShowS

                mov     cx, Block_Size
                shr     cx, 2                   ; Number of words we'll be moving
                push    cx
                shr     cx, 2                   ; CX = # of 16 byte segments

                mov     ax, KERNEL_SEG          ; Where sectors 2 - n are going to be loaded
                sub     ax, cx                  ; Leave room for kernel loader
                mov     es, ax
                xor     di, di

                mov     cx, .Load               ; Source buffer
                shr     cx, 4                   ; Determine its segment
                mov     ax, cs
                add     ax, cx
                mov     ds, ax
                xor     si, si

                pop     cx
                rep     movsd

        ; Because code can change, I wanted to make this algo dynamic, thus the RETF.
       
                mov     ax, es                  ; Build far pointer
                push    ax

                push    0
                retf                            ; Jump to it

                align   16                      ; So subsequent is aligned on segment boundry

        ; Determine metrics of media we've booted from

        .Load   sub     sp, PACKET_SIZE         ; Space for disk parameters
                mov     ax, ss
                mov     ds, ax
                mov     si, sp                  ; DS:SI = Pointer to parameters
                mov     ah, Get_D_Params
                mov     dx, [bp - 2]            ; Get drive # again
                int     DISK_IO
                jc      .Err

        ; Load in remaining sectors of this track/head

                mov     ax, KERNEL_SEG
                mov     es, ax
                xor     bx, bx                  ; ES:BX = Pointer to desintation buffer
                mov     cx, 2
                mov     al, [si + 12]
                dec     al
                mov     ah, READ_SECT
                int     DISK_IO
                jc      .Err

                add     sp, PACKET_SIZE         ; Recover space used for metrics
                jmp     KERNEL_SEG:0

        ; If we get to here, then our loader failed somewhere

          .Err  mov     ax, VIDEO_SEG           ; Point to last line of page 0
                mov     es, ax
                mov     di, 12
                mov     cx, 4
                mov     ax, 0xe4fe
                rep     stosw

                xor     ax, ax                  ; Wait for operator input
                int     KEYBOARD

                int     0x19                    ; Re-boot

    Block_Size  equ     $ - .Load