Hi maugustyniak,
Can try!
> segment .data
> addr_x dd 0,0,0,0,0,0 ; The X array
> addr_y dw 1,2,3,4,5,6 ; The Y array
> a dd 2 ; the scalar multiplier
> size db 6 ; the number of X and Y array elements to multiply by a
I'd make this "dd", too.
> msg1 dw 0xA,'The value of the array contents are: ',0xA
This wants to be "db", not "dw".
> len1 equ $-msg1
>
> segment .text
> global _start
>
> _start:
> ;; so first I set up the addresses
> mov esi,[addr_y] ; the source is the address of y
This is the root of the segfault! Remember that the "[]"s indicate *contents* of memory in Nasm syntax! To get the address, lose the "[]"!!!
> mov edi,[addr_x] ; the destination is the address of x
Likewise.
> mov ecx,[size] ; initializes the count to 6, or whatever the size of the array
> should be
Here you *do* want "[contents]", but you're moving a dword into ecx (the size of the register determines the size of the operation, in this case), but you've defined "size" as "db" - just a byte. So you're getting three bytes of whatever garbage comes after "size" into ecx. If this happens to be zero, all works as intended. If not, you loop for far longer than intended. This *could* even cause a segfault right here, if "size" happened to be the very last byte in memory you "own" (unlikely). You could "mov cl, [size]" - would work if the upper bytes of ecx were zero - you could "xor ecx, ecx" first, to be sure this is so. You could "movzx ecx, byte [size]" with the same effect. The easiest(?) thing is probably to define "size" as dword, even though the value will fit in a byte. You could not use the "loop" instruction - "dec cl"/"jnz mult_by_scalar", using only cl and not worry about the rest of ecx at all. "Programmer's Choice".
> mov bx,[a]
You've defined "a" (nice "meaningful" variable name :) as "dd". This won't hurt, but it "wastes" the two bytes after 02 00. It would be more "right" to define "a" as "dw", or use ebx here. You can load ebx here and still "mul bx" (with correct results in this case). Since the assignment apparently specifies that this is "word" (16 bits), the "right" thing is probably to define "a" as "dw".
> mult_by_scalar:
> mov ax,[esi] ; segmentation fault, it's not picking up my addr_y or addr_x
... caused by the wrong thing in esi, above. Although the segfault occurs here, this code is fine. The error is where you load esi.
> mul bx ; then we multiply ax by the value at a, the product is stored as
> dx:ax
> ;; Now we have to move our result from dx:ax into our X vector, this
> ;; will have to be done in two steps:
> ;; 1)we shift the lower 16 bits of edx into the higher bits
> ;; hence we move dx into the extended part of edx, we thus move the
> ;; half of our product aY (at the current index of Y)
> ;; 2)we move ax, which contains the lower 16 bits of our product into
> ;; dx, which is filled with 0s as a result of step 1, hence we join
> ;; the product of a*Y in one register edx instead of having
> ;; it concatenated into two 16 bit registers dx:ax
> shl edx,16 ; we move dx into the extended part of edx not the problem
> mov dx,ax ; and we move the remaining part of the result iinto ax so that
> if follows
> ; the first 16 bits
>
> mov [edi],edx ; segmentation fault, a segmentation fault occurs when you attempt
> to access an unwritten
> ; memory location
If we had the address in edi (no "[]" when you load edi above), this would work. Instead of getting dx:ax into a single register, you could also have done "mov [edi], ax"/"mov [edi + 2], dx" - does the same thing.
> add esi,2
> add edi,4
> loop mult_by_scalar ;decrements esi until it reaches 0 and then it ;craps
> out
"Comment does not match code." - you mean ecx, not esi, of course.
> ;; So now we output the result
> ;; mov esi,addr _x
> ;; mov ecx,0
> ;; output: mov eax,4
> ;; mov ebx,1
> ;; mov esi,ecx
> ;; push ecx
> ;; mov ecx,addr_x
> ;; add ecx,esi
> ;; mov edx,4
> ;; int 0x80
> ;; pop ecx
> ;; inc ecx
> ;; cmp ecx,[size]
> ;; jl output
Nice try, but this isn't going to work. What you've got in your "addr_x" buffer is a number - a dword, so yeah, it takes up four bytes. But what we want to print is a series of ascii characters representing that number (presumably, as decimal). It could take as many as 10 (or only one) characters to print a dword.
To print a single (decimal) digit, we need to add 30h, or 48 decimal, or '0' to the number, to convert it to the right ascii character ("numeral", if you will).
To print a number that takes more than one digit to represent, we need to separate out the digits, and convert 'em to ascii one at a time. The "div" instruction - by ten, for decimal representation - will give us the quotient in eax, and the remainder in edx. Hang on to the quotient, so we can "div" it again - if we keep doing this until the quotient is zero, the remainders are the digits we want to print (after converting 'em to ascii!), but in the "wrong order". So, as we accumulate remainders in edx, we want to convert 'em to ascii and store 'em starting at the "end" of the buffer, and work toward the "front". (or you can push 'em on the stack, and pop 'em off in the right order to print). There's a "gotcha" with the "div" instruction - it divides edx:eax by what you say (a dword), not just eax. If we fail to make edx zero before the "div", we'll get wrong results, or cause an exception!
I've posted routines to do this "display a number" trick several times. Typically, what I post is intended as a "throwaway" routine - for debugging purposes mostly. It's "good" for that, since it doesn't require an explicitly allocated buffer, it uses the stack. A more flexible routine would be like "itoa()", and would take a buffer (address) as a parameter, as well as the number to convert. Then you can print the buffer when and how you like. A nice enhancement might be to "right justify" the numbers, so they'll print with the columns lined up, no matter how many digits... It would make the output of your program look nicer ("just like C" :)
> exit:
> mov eax,1
> mov ebx,0
> int 0x80
Good! :)
Best,
Frank