NASM - The Netwide Assembler

NASM Forum => Programming with NASM => Topic started by: maplesirop on March 07, 2013, 02:30:55 AM

Title: what's wrong with my code
Post by: maplesirop on March 07, 2013, 02:30:55 AM
Code: [Select]
segment .data

matrix dw 12, 8, 23,
          19, 6, 14,
          24, 18, 4,

matrix2 dw 23, 2, 12,
           23, 2, 12,
           23, 2, 12,

segment .bss

segment .text

mov di, 0
mov si, 0
mov cx, 5

label1: cmp di, 18
jae label4
mov si, 0

label2: cmp si, 4
ja label3
mul
mov ax, matrix[di+si]
mul 10
add si, 2
jmp label2

label3: add di, 6
jmp label1

label4: mov eax, 1
xor ebx, ebx
int 0x80

$ nasm -f elf nasm.asm
nasm.asm:4: error: label or instruction expected at start of line
nasm.asm:5: error: label or instruction expected at start of line
nasm.asm:8: error: label or instruction expected at start of line
nasm.asm:9: error: label or instruction expected at start of line
nasm.asm:26: error: comma, colon or end of line expected

I am trying to multiply matrix with 10, but the program won't compile.
Title: Re: what's wrong with my code
Post by: Mathi on March 07, 2013, 07:31:46 AM
1. Use backslash '\' when you want the next line to be part of the current statement.
2. Your program should have an entry point . _start preferably.
3. You are compiling your program in 32 bit mode for linux which means when it comes to addressing your variables you should always use 32 bit registers (eax, ebx, esi, edi ) instead of ax,bx, si, di.
4. you can use imul instruction when you need to multiply ax by an integer constant or you need to do use another register to hold the value 10.
like,
mov cx, 10
mul cx

Plz try with the below changes and let us know. All the best.

Code: [Select]
global _start
segment .data

matrix dw 12, 8, 23, \
          19, 6, 14, \
          24, 18, 4

matrix2 dw 23, 2, 12, \
           23, 2, 12, \
           23, 2, 12

segment .bss

segment .text
_start:
mov edi, 0
mov esi, 0
mov cx, 5

label1: cmp di, 18
jae label4
mov si, 0

label2: cmp si, 4
ja label3
lea ebx, [matrix+edi+esi]  ;; this stores in ebx the address of matrix[i,j]
mov ax, word[ebx]          ;; this gets the value of matrix[i,j] in ax.
imul ax,10                 ;; ax = ax*10
mov word[ebx], ax          ;; matrix[i,j] = ax
add si, 2
jmp label2

label3: add di, 6
jmp label1

label4: mov eax, 1
xor ebx, ebx
int 0x80
Title: Re: what's wrong with my code
Post by: Frank Kotler on March 07, 2013, 08:25:05 AM
Well...

Code: [Select]
segment .data

matrix dw 12, 8, 23,
          19, 6, 14,
          24, 18, 4,

matrix2 dw 23, 2, 12,
           23, 2, 12,
           23, 2, 12,

As the error message says, Nasm is expecting a label or instruction at the start of a line. Unlike C, assembler is "line oriented" and won't continue on to the next line... unless we give it the line-continuation character '\'...

Code: [Select]
segment .data

matrix dw 12, 8, 23,\
          19, 6, 14,\
          24, 18, 4,

or, as an alternative, put an instruction (pseudo-instruction, actually) at the start of a line...

Code: [Select]
segment .data

matrix dw 12, 8, 23,
       dw 19, 6, 14,
       dw 24, 18, 4,

Nasm will conveniently ignore the trailing commas, although they probably really shouldn't be there. As a third alternative, string 'em all out on one line - more readable the way you've got it.

Then... despite the fact that you're assembling to 32-bit code, you're using 16-bit registers, 16-bit instructions, and so you're stuck with 16-bit addressing modes: an optional offset, plus an optional base register (bx or bp), plus an optional index register (si or di). Two index registers is no go! In 32-bit addressing modes, any register can be a base register and any but esp can be an index register (we also get an optional scale, 1, 2, 4, or 8, to be multiplied by the index register). Also, Nasm expects the offset ("matrix") to be inside the square brackets. "mov ax, [matrix + esi + edi]" will assemble - really ought to make sure the upper bits of esi and edi are zero! Using bx for one of the registers would also work.

Then... you haven't got a valid operand on either of your "mul"s. I didn't know what the first one was supposed to do, so I commented it out. I put "ten dw 10" in the .data section and did "mul word [ten]". "mul" won't allow an immediate operand - "imul" will ("imul" is actually a couple of different instructions).

At this point, it'll assemble... but ld whines about not finding an enterypoint (it actually does the right thing). Add "global _start" and a "_start:" label... There! Silence!

It's hard to say if it "works" or not. You do the "mul" but don't do anything with the result. I suppose you're going to put it in a "result_matrix" or something...

In 32-bit code, it isn't easier, shorter, or faster to use 16-bit instructions. I'd do it all in 32-bit. If you really need to limit yourself to 16-bit numbers, okay use 16-bit registers/instructions there... but the addresses are still 32-bit!

Well, as usual, I've been too slow and Mathi has posted a better answer. Thanks Mathi!

Best,
Frank

Title: Re: what's wrong with my code
Post by: maplesirop on March 07, 2013, 08:22:57 PM
Hi, thanks for your answers.

Do you know why this lines gives me an error?

mov ax, matrix[di + si]

it gives me: nasm.asm:26: error: comma, colon or end of line expected

Code: [Select]
segment .data

matrix dw 12, 8, 23,\
          19, 6, 14,\
          24, 18, 4

matrix2 dw 0, 0, 0,\
           0, 0, 0,\
           0, 0, 0,

segment .bss

segment .text

mov di, 0
mov si, 0
mov cx, 5

label1: cmp di, 18
jae label4
mov si, 0

label2: cmp si, 4
ja label3
mul
mov ax, matrix[di + si]
mov cx, 10
mul cx
mov matrix2[di + si], ax
add si, 2
jmp label2

label3: add di, 6
jmp label1

label4: mov eax, 1
xor ebx, ebx
int 0x80




I want the output in matrix2. Would this work?  I don't want to use indirect addressing [matrix + di + si]
Title: Re: what's wrong with my code
Post by: Frank Kotler on March 07, 2013, 11:53:57 PM
Again... despite the fact that you're assembling to 32-bit code, you're using 16-bit registers, 16-bit instructions, and so you're stuck with 16-bit addressing modes: an optional offset, plus an optional base register (bx or bp), plus an optional index register (si or di). Two index registers is no go! In 32-bit addressing modes, any register can be a base register and any but esp can be an index register (we also get an optional scale, 1, 2, 4, or 8, to be multiplied by the index register). Also, Nasm expects the offset ("matrix") to be inside the square brackets. "mov ax, [matrix + esi + edi]" will assemble - really ought to make sure the upper bits of esi and edi are zero! Using bx for one of the registers would also work.

Best,
Frank

Title: Re: what's wrong with my code
Post by: maplesirop on March 10, 2013, 03:17:50 AM
Thank you for responding.

I get:

nasm.asm:25: error: invalid combination of opcode and operands

Code: [Select]
segment .data

matrix dw 12, 8, 23,\
          19, 6, 14,\
          24, 18, 4

matrix2 dw 0, 0, 0,\
           0, 0, 0,\
           0, 0, 0,

segment .bss

segment .text

mov edi, 0
mov esi, 0
mov ecx, 5

label1: cmp edi, 18
jae label4
mov si, 0

label2: cmp esi, 4
ja label3
mul
mov eax, [matrix + edi + esi]
mov ecx, 10
mul ecx
mov [matrix2 + edi + esi], ax
add esi, 2
jmp label2

label3: add edi, 6
jmp label1

label4: mov eax, 1
xor ebx, ebx
int 0x80

Would it work if I remove mul in line 25?
Title: Re: what's wrong with my code
Post by: Frank Kotler on March 10, 2013, 06:50:46 AM
What happens when you try it? What is the intended purpose of that "mul"? I don't "get it".

Without having tried it (yet), I would say that it will assemble. It may not be fully "right" yet...

Code: [Select]
...
;mul
mov eax, [matrix + edi + esi]

At this point, you're loading from the correct address (and correct Nasm syntax), but you're loading 4 bytes - two of your "dw" numbers. One of 'em goes in ax, and the other in the upper bits of eax (which don't have a special name). This might be "close enough", but it isn't really what you want to do...

Code: [Select]
mov ecx, 10
mul ecx

"mul" is a tricky instruction, as there's an implied operand besides the "ecx" that's showing, and the implied operand varies with the size of the operand shown...

Code: [Select]
mul cl
will multiply al times cl and put the result in ax.
Code: [Select]
mul cx
will multiply ax times cx and put the result in dx:ax. That is, dx times 64k plus ax. If the result overflows a 16-bit number - ax - the overflow goes in dx. This is probably the one you want, although you can probably ignore the overflow for now. If you put a number in your matrix that will overflow 16 bits when multiplied by ten, that's where it'll be. You might want to print "the number is too big" or you might want to print the entire result.
Code: [Select]
mul ecx
multiplies eax times ecx and puts the result in edx:eax - edx times 4G plus eax. This is what you're doing. But then you:
Code: [Select]
mov [matrix2 + edi + esi], ax
That's right - you only want a 16-bit number in your result matrix. Now we started with a "wrong" value in eax, but the "right" value in ax. Then we multiplied all of eax by ten. I don't think this can cause any "back contamination" into ax, so I think you're going to get the right result... but I'd still rather see you using ax and "mul cx"...

I don't know why you're using 16-bit numbers. Perhaps that's the "customer specification" (aka "assignment"). It's just as easy to do it with 32-bit numbers - just change the definition of "matrix" to "dd". (oh, yeah... and change the increments on esi and edi) When it comes time to display the result, that will probably be easier using 32-bit numbers too. If you can...

Best,
Frank

Title: Re: what's wrong with my code
Post by: Gerhard on March 10, 2013, 10:40:40 AM
Hi maplesirop,

Frank is right: 16 bit coding is very awkward. I would change the entire code to 32 bit, which is a lot more comfortable.

Take care.

Gerhard
Title: Re: what's wrong with my code
Post by: maplesirop on March 11, 2013, 12:20:09 AM
Code: [Select]
segment .data

matrix dd 12, 8, 23,\
          19, 6, 14,\
          24, 18, 4

matrix2 dd 0, 0, 0,\
           0, 0, 0,\
           0, 0, 0,

segment .bss

segment .text

mov edi, 0
mov esi, 0
mov ecx, 5

label1: cmp edi, 18
jae label4
mov esi, 0

label2: cmp esi, 4
ja label3
mov eax, [matrix + edi + esi]
mov ecx, 10
mul ecx
mov [matrix2 + edi + esi], edx
add esi, 2
jmp label2

label3: add edi, 6
jmp label1

label4: mov eax, 1
xor ebx, ebx
int 0x80

Ok, thanks. I tried to fix the code. Would this work?
Title: Re: what's wrong with my code
Post by: maplesirop on March 11, 2013, 12:48:23 AM
Also, I'd like to know when the value of eax, edi and esi is flushed out of the stack in this program.



Code: [Select]
label5: mov eax, 4
mov ebx, 1

mov eax, 1
xor ebx, ebx
int 0x80

Also, would this print whatever value we have in ecx and then close the program?
Title: Re: what's wrong with my code
Post by: Frank Kotler on March 11, 2013, 11:03:55 AM
What do you mean, "Would this work?"? Are you still unable to try this?  Well, you're doing pretty good, but it isn't quite right yet. I didn't do a good job of explaining what's in edx after the "div". And to move from one dword to another, we need to add 4 to esi, not 2. This throws off some of the other numbers, too. Without a routine to print the matrix, it's hard to tell if it's working or not. Doesn't segfault. :)

I don't know what you mean about eax, edi, and esi being "flushed out of the stack". We haven't put 'em on the stack, have we?

No, you can't print the value in ecx with sys_write. ecx points to memory, where if we're lucky there are some characters. If we're really lucky, they might be  characters representing some number we're interested in. You didn't like the macro. You could "just call printf" - that's fairly easy and does a nice formatting job. Or maybe you'll like this approach... I'm not very happy with it, but I guess it "works".

Code: [Select]
global _start

segment .data

matrix dd 12, 8, 23,\
          19, 6, 14,\
          24, 18, 4

matrix2 dd 0, 0, 0,\
           0, 0, 0,\
           0, 0, 0,

linefeed db 10

segment .bss
ascbuf resb 12 ; buffer to convert number to text

segment .text

_start:  ; <-

mov edi, 0
mov esi, 0
mov ecx, 5

label1: cmp edi, 36 ; <-
jae label4
mov esi, 0

label2: cmp esi, 8 ; <-
ja label3
mov eax, [matrix + edi + esi]
mov ecx, 10
mul ecx
mov [matrix2 + edi + esi], eax ; <-
add esi, 4 ; <-
jmp label2

label3: add edi, 12 ; <-
jmp label1

label4:
; print the matrix...

    mov esi, 0 ; index into our matrix

label5:
    mov eax, [matrix2 + esi * 4]
    mov ebx, 10 ; divisor
    mov edi, 0 ; character counter (like to use edx, but it's busy)
    mov ecx, ascbuf + 11 ; start at the end of the buffer

; end with a comma?
    mov byte [ecx], '.'
    dec ecx
    inc edi
label6:
    mov edx, 0 ; "div" is using edx:eax
    div ebx ; quotient in eax, remainder in edx
    add dl, '0' ; convert digit to character
    mov [ecx], dl ; store it
    dec ecx  ; working backwards in the buffer
    inc edi ; count it
    cmp eax, 0 ; if quotient is zero, we're done
    jnz label6 ; else do more

label7:

; pad to the beginning of the buffer with spaces
    cmp ecx, ascbuf
    je label8
    mov byte [ecx], ' '
    dec ecx
    inc edi
    jmp label7
label8:
    inc edi
; ecx should be all set for the sys_write
    mov edx, edi
    mov ebx, 1 ; stdout
    mov eax, 4 ; __NR_write
    int 0x80
; do we need a newline?
    mov eax, esi
    mov ebx, 3
    xor edx, edx
    div ebx
    cmp edx, 2
    jnz label9
; then do one!
    mov edx, 1
    mov ecx, linefeed
    mov ebx, 1
    mov eax, 4
    int 0x80

label9:
    inc esi
    cmp esi, 9
    jnz label5
   
mov eax, 1
xor ebx, ebx
int 0x80

If you're not able to run this, maybe you should look into some Windows examples. It won't hurt you. Wash your hands after. :)

Best,
Frank

Title: Re: what's wrong with my code
Post by: Gerhard on March 11, 2013, 05:37:31 PM
Hi Frank,

If you're not able to run this, maybe you should look into some Windows examples. It won't hurt you. Wash your hands after. :)

good joke, but it's right.  8)

Gerhard
Title: Re: what's wrong with my code
Post by: maplesirop on March 12, 2013, 04:13:20 PM
What do you mean, "Would this work?"? Are you still unable to try this?  Well, you're doing pretty good, but it isn't quite right yet. I didn't do a good job of explaining what's in edx after the "div". And to move from one dword to another, we need to add 4 to esi, not 2. This throws off some of the other numbers, too. Without a routine to print the matrix, it's hard to tell if it's working or not. Doesn't segfault. :)

I don't know what you mean about eax, edi, and esi being "flushed out of the stack". We haven't put 'em on the stack, have we?

No, you can't print the value in ecx with sys_write. ecx points to memory, where if we're lucky there are some characters. If we're really lucky, they might be  characters representing some number we're interested in. You didn't like the macro. You could "just call printf" - that's fairly easy and does a nice formatting job. Or maybe you'll like this approach... I'm not very happy with it, but I guess it "works".

Code: [Select]
global _start

segment .data

matrix dd 12, 8, 23,\
          19, 6, 14,\
          24, 18, 4

matrix2 dd 0, 0, 0,\
           0, 0, 0,\
           0, 0, 0,

linefeed db 10

segment .bss
ascbuf resb 12 ; buffer to convert number to text

segment .text

_start:  ; <-

mov edi, 0
mov esi, 0
mov ecx, 5

label1: cmp edi, 36 ; <-
jae label4
mov esi, 0

label2: cmp esi, 8 ; <-
ja label3
mov eax, [matrix + edi + esi]
mov ecx, 10
mul ecx
mov [matrix2 + edi + esi], eax ; <-
add esi, 4 ; <-
jmp label2

label3: add edi, 12 ; <-
jmp label1

label4:
; print the matrix...

    mov esi, 0 ; index into our matrix

label5:
    mov eax, [matrix2 + esi * 4]
    mov ebx, 10 ; divisor
    mov edi, 0 ; character counter (like to use edx, but it's busy)
    mov ecx, ascbuf + 11 ; start at the end of the buffer

; end with a comma?
    mov byte [ecx], '.'
    dec ecx
    inc edi
label6:
    mov edx, 0 ; "div" is using edx:eax
    div ebx ; quotient in eax, remainder in edx
    add dl, '0' ; convert digit to character
    mov [ecx], dl ; store it
    dec ecx  ; working backwards in the buffer
    inc edi ; count it
    cmp eax, 0 ; if quotient is zero, we're done
    jnz label6 ; else do more

label7:

; pad to the beginning of the buffer with spaces
    cmp ecx, ascbuf
    je label8
    mov byte [ecx], ' '
    dec ecx
    inc edi
    jmp label7
label8:
    inc edi
; ecx should be all set for the sys_write
    mov edx, edi
    mov ebx, 1 ; stdout
    mov eax, 4 ; __NR_write
    int 0x80
; do we need a newline?
    mov eax, esi
    mov ebx, 3
    xor edx, edx
    div ebx
    cmp edx, 2
    jnz label9
; then do one!
    mov edx, 1
    mov ecx, linefeed
    mov ebx, 1
    mov eax, 4
    int 0x80

label9:
    inc esi
    cmp esi, 9
    jnz label5
   
mov eax, 1
xor ebx, ebx
int 0x80

If you're not able to run this, maybe you should look into some Windows examples. It won't hurt you. Wash your hands after. :)

Best,
Frank

Thanks, I think I can run it on my computer but I have to shut down and then run linux and upload the assembled code through my usb key.

Code: [Select]
label4:
; print the matrix...

    mov esi, 0 ; index into our matrix

label5:
    mov eax, [matrix2 + esi * 4]
    mov ebx, 10 ; divisor
    mov edi, 0 ; character counter (like to use edx, but it's busy)
    mov ecx, ascbuf + 11 ; start at the end of the buffer

; end with a comma?
    mov byte [ecx], '.'
    dec ecx
    inc edi
label6:
    mov edx, 0 ; "div" is using edx:eax
    div ebx ; quotient in eax, remainder in edx
    add dl, '0' ; convert digit to character
    mov [ecx], dl ; store it
    dec ecx  ; working backwards in the buffer
    inc edi ; count it
    cmp eax, 0 ; if quotient is zero, we're done
    jnz label6 ; else do more

label7:

; pad to the beginning of the buffer with spaces
    cmp ecx, ascbuf
    je label8
    mov byte [ecx], ' '
    dec ecx
    inc edi
    jmp label7
label8:
    inc edi
; ecx should be all set for the sys_write
    mov edx, edi
    mov ebx, 1 ; stdout
    mov eax, 4 ; __NR_write
    int 0x80
; do we need a newline?
    mov eax, esi
    mov ebx, 3
    xor edx, edx
    div ebx
    cmp edx, 2
    jnz label9
; then do one!
    mov edx, 1
    mov ecx, linefeed
    mov ebx, 1
    mov eax, 4
    int 0x80

label9:
    inc esi
    cmp esi, 9
    jnz label5
   
mov eax, 1
xor ebx, ebx
int 0x80

If I understand correctly, this bit of code is used to print all the elements of the matrix, right?
Title: Re: what's wrong with my code
Post by: maplesirop on March 12, 2013, 04:16:09 PM
Code: [Select]
mov di, 0
mov si, 0
mov cx, 5

I understand what the first 2 lines do, but I don't understand what the third line does.
Title: Re: what's wrong with my code
Post by: maplesirop on March 12, 2013, 05:43:29 PM
[andric] [/home/j/jo_smi] > nasm -f elf ex.asm
[andric] [/home/j/jo_smi] > ld ex.o -o ex
ld: warning: i386 architecture of input file `ex.o' is incompatible with i386:x86-64 output
[andric] [/home/j/jo_smi] > . / ex
/usr/bin/.: Permission denied.
[andric] [/home/j/jo_smi] > ./ex

the code doesn't work












Title: Re: what's wrong with my code
Post by: Frank Kotler on March 12, 2013, 08:23:21 PM
Quickly... for a 64-bit system, we need to tell ld we want 32-bit code...
Code: [Select]
ld ex.o -o ex -melf_i386

More later,
Frank

Title: Re: what's wrong with my code
Post by: maplesirop on March 13, 2013, 12:25:52 AM
can I do this?

mov ecx, 40
mov eax, 4
mov ebx, 1

I don't quite understand why we can't use ecx?
Title: Re: what's wrong with my code
Post by: Frank Kotler on March 13, 2013, 10:47:15 AM
Sure you can use ecx. If this is supposed to be the setup for a sys_write, 40 isn't going to be valid memory to find the buffer...

In my "print the matrix" routine, I used ecx as a pointer into the buffer as I filled it up with digits/characters so it was supposed to be "all set" when I got to the sys_write, but I screwed up! I decremented ecx to the beginning of my buffer, but didn't put a space in the last [ecx]. A classic "fencepost" or "off-by-one" error. My bad! It kinda works okay anyway, but it definitely isn't right. I'll fix it if I'm in the mood...

The "mov cx, 5" was left over from your code. Doesn't do any good, but it doesn't do any harm. I tried to leave your code alone (consistent with making it work with dwords) and just add the "print the matrix" routine so you could track down what was happening more easily... and I didn't even get that right... sigh...

Best,
Frank

Title: Re: what's wrong with my code
Post by: maplesirop on March 13, 2013, 04:06:38 PM
Code: [Select]
digits db "aa", 0xA, 0XD
length equ $ -digits

mov eax, 4
mov ebx, 1
mov ecx, 3
mov edx, length
 

What is the problem with this code?

Title: Re: what's wrong with my code
Post by: maplesirop on March 13, 2013, 08:01:57 PM
Ok, I tried using printf, but I get segmentation fault errors. Why is that?
Title: Re: what's wrong with my code
Post by: Frank Kotler on March 13, 2013, 08:10:09 PM
Well, your first code looks like it's going to execute the data. My crystal ball tells me you're probably mutilating the stack, trying to use "printf"...

Best,
Frank

Title: Re: what's wrong with my code
Post by: maplesirop on March 13, 2013, 09:27:01 PM
Thanks.

I don't really understand how the stack works... Do i have to clean it at the end of each label? When do I have to clean it?

Someone said I got fragmentation fault because I was running a 32 bit code in a 64 bit machine. Is he right?
Title: Re: what's wrong with my code
Post by: Frank Kotler on March 13, 2013, 11:37:43 PM
Probably. I haven't got a 64-bit nachine, so I don't know what it'll do. 32-bit code should run fine on a 64-bit machine. Source code suitable for 32-bit code, assembled to a 32-bit linkable file, and linked to some mysterious hybrid of 32- and 64-bit code is probably "undefined"... but it doesn't seem to be working out well!

You and I have both posted examples of "cleaning up the  stack" to the "printing in asm" topic. Probably better to discuss it there...

Best,
Frank

Title: Re: what's wrong with my code
Post by: maplesirop on March 14, 2013, 08:55:48 PM
can we compare

[matrix + edi + esi]

and

[matrix + edi + esi + 4]

it seems that it doesn't work, but i am not sure and when is the stack cleared?
Title: Re: what's wrong with my code
Post by: Frank Kotler on March 15, 2013, 04:42:39 AM
Ummm... you mean like?
Code: [Select]
cmp [matrix + edi + esi], [matrix + edi + esi + 4]
? No, we can't. Only one memory reference at a time, generally (we only have one address bus). We'd have to do:
Code: [Select]
mov eax, [matrix + edi + esi]
cmp [matrix + edi + esi + 4], eax

I'm not sure what you mean about the stack...
Code: [Select]
push eax
push ebx
push ecx
push format_string
call printf
add esp, 16 ; <- "remove" 4 parameters from stack

Like that?

Best,
Frank