Author Topic: Simple array  (Read 24394 times)

Offline c0dehunter

  • Jr. Member
  • *
  • Posts: 8
Simple array
« on: November 27, 2010, 10:50:55 PM »
Hello dear members, i've been working on an assignment for quite a time now but i need some further tips..

Task:
In assembly language, write a function that receives a pointer to an array of integers and the size of this array, and changes the array by reversing its elements. Use the dedicated instructions and registers to work with arrays (esi, edi; lodsb, stosb, cld, std).

Example: 1 2 3 4 5 -> 5 4 3 2 1

This is what i have done:
Code: [Select]
bits 32
extern _printf
global _main

section .data
array db 9,2,3,4,5
VELIKOST equ $ - array
format_out db "%d",10,0
section .text
_izpisi:
mov eax,[array+4] //i want to read the first number, 9

push eax
push dword format_out
call _printf //and print it out
add esp,8

ret



_main:
pushad ;preserve registers

call _izpisi

popad ;restore registers
ret

I want to display the first number in array, and then possibly reading next with +8,+12, etc..
If someone could help me i'd really appreciate it!

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Simple array
« Reply #1 on: November 28, 2010, 06:01:19 AM »
Hi C0dehunter,

In the zeroth place, "//" is not a comment character in Nasm, ";" is, so this won't even assemble!

In the first place, "array of integers" would imply dwords (in 32-bit code). You've got your array declared "db". You want "dd".

In the second place, "[array + 4]" would address the second integer - the first one would be "[array + 0]" (or just "[array]", but I'd use the "+ 0" for clarity). "mov eax, [anything]" is going to move 4 bytes, so with your array declared "db", you're picking up several numbers... some of 'em past the end of the array! :( Comes to 174 million and change - not even close!

If you make those changes one at a time, you'll see what I mean.

Now... you could address your array as [array + 0], [array + 4], [array + 8], etc. Not too bad for five elements, but if the array got larger, it'd be pretty tedious! I'd think of "[array + ebx]", with ebx taking the values 0, 4, 8, 12, 16. Better yet, "[array + ebx * 4]", with ebx taking values 0, 1, 2, 3, 4.

However... your assignment specifically tells you to use lodsb, stosb, etc. I'm confused! lodsb, stosb would load and store bytes - lodsd, stosd would work with dwords. Maybe your "integers" are supposed to be bytes, after all! Better ask your instructor for guidence on this issue. It matters! I think I'll ASSume "integers" means dwords, and you're supposed to use lodsd/stosd.

The assignment specifies that your function should receive a pointer to the array and its size as parameters - presumably on the stack. Do you know how to do that part? I think you mentioned that you had to do it in that "recursive" example you posted earlier. There should be examples around...

Now my first thought would be to set esi at the beginning of the array, and edi to the last element in the array - not the end of the array, but the last element(!). Then do something like...

Code: [Select]
lodsd
std
stosd
cld
; until done

But that isn't going to work! I'm going to be overwriting elements that haven't been moved yet! My bad! Although the assignment implies that the array is to be reversed "in place", I think we're going to need a temporary array! "On the stack" would be handy. In fact, if we just push the array elements on the stack, we can pop 'em off "reversed" (Last In, First Out). That's probably the way I'd do it, but it doesn't involve lodsb/lodsd, stosb/stosd, std, cld at all.

Come to think of it, I don't have the slightest idea how you're "supposed" to do this assignment, as stated. Lemme fool with it, and see if I can figure something out. You see if you can get some clarity on the assignment - are we using an array of bytes, or does "integers" mean dwords? Do you really have to use "std"?

Later,
Frank


Offline c0dehunter

  • Jr. Member
  • *
  • Posts: 8
Re: Simple array
« Reply #2 on: November 28, 2010, 08:02:48 AM »
Hello again Frank,
thanks for you input, I have acknowledged and understand your post. I will ask our teacher about this "integers" matter. Your version (pushing numbers on stack and then popping them) seem quite more elegant.

Until then I can make further progress...

/*edited one hour later:
So, I have done this task using your way, Frank, and it's a really nice solution. I will try to code the other version too just so i am sure.

Frank, thank you for your help - it really helped me to understand NASM a bit more :)

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Simple array
« Reply #3 on: November 28, 2010, 10:04:24 PM »
Good! After further thought, I came up with this, which uses lodsd, stosd, cld, and std, as specified. I realized that we don't need a "temporary array" if we save eax to another register, and stop when we get to the "middle" (or beyond). It isn't what I'd call "elegant" (by a lot!), but it does work - and uses the requested instructions.

Code: [Select]
_reverse_dword_array:
    push ebp
    mov ebp, esp

    push esi
    push edi
   
    mov esi, [ebp + 8]  ; address of array
    mov ecx, [ebp + 12]  ; size of array (in bytes, not elements)
    mov edi, esi  ; edi -> start of array
    add edi, ecx  ; edi -> end of array
    sub edi, 4    ; edi -> last element in array

.top:
    lodsd          ; first, or bottom element to eax, esi = esi + 4
    mov ecx, eax   ; save it
    xchg esi, edi  ; esi -> top, edi -> bottom
    std            ; set direction flag - working downward
    lodsd          ; last, or top element to eax, esi = esi - 4
    cld            ; clear direction flag - "going up"
    sub edi, 4     ; undo the "+ 4" from first lodsd
    stosb          ; former last (or top) element to first (or bottom) edi = edi + 4
    mov eax, ecx   ; saved first (bottom) element back to eax
    xchg esi, edi  ; esi -> bottom, edi -> top
    std            ; going down
    add edi, 4     ; undo second lodsd (direction flag was set)
    stosb          ; former "bottom" element to "top" - edi = edi - 4
    cld            ; going up
    cmp esi, edi   ; if esi = edi (odd nember of elements) or above (even number of elements)
    jb .top        ; we're done - else do more
   
    pop edi
    pop esi

    mov esp, ebp
    pop ebp
    ret
   

If we don't insist on using the "string instructions", we can do the same thing, much simpler, by deferring the + and - until we're "ready":

Code: [Select]
...
mov eax, [esi]
mov ecx, [edi]
mov [esi], ecx
mov [edi], eax
add esi, 4
sub edi, 4
...

(untested!) Pushing elements onto the stack and popping them off should also work. The "string instructions" are great - short (and I like short code!), but not always "appropriate" to the intended purpose.

Best,
Frank


Offline c0dehunter

  • Jr. Member
  • *
  • Posts: 8
Re: Simple array
« Reply #4 on: November 30, 2010, 11:50:53 AM »
Why doesnt this work (i want to print out)?

Code: [Select]
array db 9,2,3,4,5
format_out db "%d",10,0
....
                mov esi,array
                push esi
push dword format_out
call _printf
add esp,8

push dword [array] also doesn't work - i get big number, i guess it's the memory location.

Offline Rob Neff

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 429
  • Country: us
Re: Simple array
« Reply #5 on: November 30, 2010, 12:52:16 PM »

hint: is your big number 17193 (0x4329)?
Understand the format string you passed to printf and the storage location size of your data. ;)

Offline c0dehunter

  • Jr. Member
  • *
  • Posts: 8
Re: Simple array
« Reply #6 on: November 30, 2010, 01:05:16 PM »
No, the number i get is 4202496.

I thought of that format_out, yes. I thought of replacinf %d which is for dword with another one, for example %c, but then it doesn't print out nothing.

Offline Rob Neff

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 429
  • Country: us
Re: Simple array
« Reply #7 on: November 30, 2010, 01:11:42 PM »
Tell me what you get when you change

array db 9, 2, 3, 4, 5

to

array dd 9, 2, 3, 4, 5

Offline c0dehunter

  • Jr. Member
  • *
  • Posts: 8
Re: Simple array
« Reply #8 on: November 30, 2010, 02:04:49 PM »
I get the correct number, 9 :)

I have solved this puzzle:

Code: [Select]
xor eax,eax
mov al,byte [array+ebx]
push eax
push dword format_out
call _printf
add esp,8

because it's byte you have to store it in AL, which is the 8bit register included in eax..

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Simple array
« Reply #9 on: November 30, 2010, 05:49:32 PM »
You got it. "xor eax, eax" first to make sure the upper bits of eax are clear, and move your number into al. "movzx" does about the same thing. "movsx" would "sign extend" a byte (or word) into a dword. If you wanted to handle negative numbers (bytes), this might work better...

http://home.myfairpoint.net/fbkotler/nasmdocc.html#section-A.4.181

The big number 4202496 is, in hex, 0x402000 - a plausible address for Windows to start data. "mov esi, array" - address, "mov esi, [array]" - contents (but dword - this would give you what Rob said).

Code: [Select]
mov esi, array ; address
.top:
movsx eax, byte [esi] ; byte "[contents]", sign-extended to preserve "negativeness"
push eax
push format_out
call _printf
add esp, 8
inc esi ; point to next byte
... ; until done

Untested!

Probably, instead of hard-coding "array" into the routine, passing the address and size of the array as parameters, as you did(?) for the "reverse array" routine, would give more "reuseable" code.

(Oh, oh! Just tried my "solution" with negative numbers - still dwords - and it didn't work! Reason: typos! I wrote "stosb" where I meant "stosd" in two places in the code I posted. My bad! How come nobody caught that? Oh, well - it serves as an illustration that code can "work", for certain values, but still be buggy! I'm embarrassed!)

FacePalm,
Frank


Offline c0dehunter

  • Jr. Member
  • *
  • Posts: 8
Re: Simple array
« Reply #10 on: November 30, 2010, 06:27:59 PM »
Frank, I saw that stosb in your code and i was sure you mistyped it, so i just coded it "right" :)

Thanks to both, you deserve an irish beer  :D

Offline Jani_9

  • New Member
  • Posts: 1
Re: Simple array
« Reply #11 on: November 30, 2010, 07:02:25 PM »
I also have to do something similar, but whith a char array, so it is quite the same. Could you show me your hole code, codehunter?

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Simple array
« Reply #12 on: November 30, 2010, 09:54:27 PM »
Why don't you show us what you've got so far, first? If c0dehunter shows you his code, you'll both be "cheating". Strictly speaking, you'll both be "cheating" if you show your code, too. I happen to think that "sharing code" and "cooperating to solve a problem" are excellent ideas, and are what schools should be teaching. Schools, generally, do not agree. They're apt to take it quite seriously. Be careful!

Best,
Frank