NASM - The Netwide Assembler

NASM Forum => Using NASM => Topic started by: dstudentx on February 21, 2010, 06:13:25 AM

Title: array
Post by: dstudentx on February 21, 2010, 06:13:25 AM
How the heck to you implement an array! I've been lost for hours
any help would be greatly appreciated.
Title: Re: array
Post by: Frank Kotler on February 21, 2010, 08:47:41 AM
Code: [Select]
msg db "Hello, world!", 0

:)

Well, it's an array. Of bytes. What did you want an array of?

Code: [Select]
array dd 1, 2, 3, 4
array2 dq 1.0, 2.0, 3.14, 42.0

A multidimensional array? No such thing - lay it out "flat" and address it as "row * row_length + column * item_size".

What are you trying to do? (and what happens?)

Best,
Frank

Title: Re: array
Post by: Flybro on February 21, 2010, 09:34:06 AM
Take a look at http://www.drpaulcarter.com/pcasm/
There is long chapter in the manual about arrays.

Cheers,
F.
Title: Re: array
Post by: dstudentx on February 21, 2010, 06:14:27 PM
sorry.

I simple array of integers.
the user inputs say 

enter a number: 3
enter another number? Y
enter a number: 4
enter another number? Y
enter a number: 5
enter another number? N
you entered 3 4 5

I don't know how to store the user inputs in an array
Title: Re: array
Post by: dstudentx on February 21, 2010, 07:12:22 PM
please help im dying here.
Title: Re: array
Post by: Frank Kotler on February 21, 2010, 10:53:59 PM
Well, first reserve some memory to store it in. Since one problem you'll want to avoid is overrunning the buffer, best to "%define" a size we can compare to.

Code: [Select]
%define ARRAY_SIZE 3

section .bss
my_array resd ARRAY_SIZE

Note that this is in dwords, not bytes. You only show 3, Dr. Carter uses 100 - somewhere in between is probably what you want.

Now you need a means of obtaining some numbers to populate it with. You got that? Curiously, Dr. Carter's example calls scanf directly rather than use his "read_int". Dunno why. In any case, s'pose you've got the number in eax. You'll want to know which array element it's going in - s'pose in ecx. Keep in mind that the numbering starts at zero! If, for the benefit of zero-impaired "users", you want to let them call the zeroth element "1", you can make the adjustment, but the "real" numbering starts at zero. This means that the "last" element is "ARRAY_SIZE - 1"!

Code: [Select]
cmp ecx, ARRAY_SIZE - 1
ja no_good_index
mov [my_array + ecx * 4], eax

What you want to do at "no_good_index:" depends... If you're just filling the array sequentially, it means you're done. If you're asking the user for an element number, ask again.

To fetch 'em back, of course...

Code: [Select]
cmp ecx, ARRAY_SIZE -1
ja no_good_index_2
mov eax, [my_array + ecx * 4]

If you're calling C, keep in mind that C can trash ecx "behind your back" (if you've got your back turned). You might want to use another register if that's a problem - or push ecx before the C call and pop it after... as Dr. Carter does in his example.

Does that help? If not, which parts are giving you trouble?

Best,
Frank

Title: Re: array
Post by: travman89 on February 22, 2010, 02:37:06 AM
I was wondering if you could post a very basic walkthrough of arrays. I have this same type of problem for my assignment, and I have tried to follow dr carter's example but I do not know how to use the push and pop stack commands. Is there any way you can show the entire input and output commands. I have a grasp on loops, but the arrays are just stumping me.
Title: Re: array
Post by: dstudentx on February 22, 2010, 03:32:23 AM
I really appreciate the help but this is essentially my first program and I'm have problems everywhere.  I sample posting of code for and input of numbers would really help. 
I'm just really lost the Nasm.
Title: Re: array
Post by: dstudentx on February 22, 2010, 03:41:35 AM
This is how lost I am

Code: [Select]

;
; file: first.asm


%include "asm_io.inc"
;
; initialized data is put in the .data segment
;
segment .data
;
; These labels refer to strings used for output
;
%define ARAY_SIZE 20
prompt1 db    "Please enter a number ", 0
outmsg1 db    "You entered ", 0



;
; uninitialized data is put in the .bss segment
;
segment .bss
;
; These labels refer to double words used to store the inputs
;
input1  resd ARRAY_SIZE
input2  resd 1


;
; code is put in the .text segment
;
segment .text
        global  asm_main
asm_main:
        enter   0,0               ; setup routine
        pusha


        mov     eax, prompt1      ; print out prompt
        call    print_string

        call    read_int          ; read integer
        mov     [input2], eax     ; store into input1

cmp ecx, ARRAY_SIZE -1
        mov [input1 + ecx * 4], eax

cmp ecx, ARRAY_SIZE -1
mov [input1 + ecx * 4], eax

       
        dump_regs 1               ; dump out register values
        dump_mem 2, outmsg1, 1    ; dump out memory
endwhile:
;
; next print out result message as series of steps
;
        mov     eax, outmsg1
        call    print_string      ; print out first message
        mov     eax, [input1]     
        call    print_int         ; print out input1
           
       
       
        call    print_nl          ; print new-line

        popa
        mov     eax, 0            ; return back to C
        leave                     
        ret
Title: Re: array
Post by: travman89 on February 22, 2010, 03:56:07 AM
Does the program execute?  If it does, does the loop work?  What is the output?
Title: Re: array
Post by: dstudentx on February 22, 2010, 04:00:26 AM
are you kidding me.  it doesn't work at all.   I think in paul carters code for prime.asm we can modify it to work.  prime.asm has a while loop.  I think if we can get array input in the while loop where pretty much done.

travman89 do you go to CSUF?
Title: Re: array
Post by: lukus001 on February 22, 2010, 05:52:56 AM
dstudentx,

Ive not used %define or the like, as I myself am pretty new so I can't vouch for accuracy, but hopefully the following will be of help to you?

You've defined 'Array_size' as 20, and used that to reserve 20 dwords of space in your .bss section 'input1'.  After you got your input you store the value from eax into 'input2' which is only a single dword of allocated space (that seems backwards to me and your comment says input1, not input2).

You then compare ecx (not sure what is in ecx) to 'array_size -1' which would be 19 by all accounts?  After the comparison, there is also no conditional jumps so it would do your 'mov' instruction regardless of your cmp instruction.  You then have the same code (cmp followed by a mov) which is unnecessary since nothing has changed between the two.   Not sureon the purpose of these mov's either.

You then print your outmessage, followed by printing 'input1' which I suspect is correct, if the above was corrected from input2 to input1.

You probabily want something more along these lines :
Code: [Select]
;you will need to add to .data:
prompt2 db 'would you like to add another number? Please press y or n',0


asm_main:
        enter   0,0               ; setup routine
        pusha

mov edx,0 ;reset our counter

        mov     eax, prompt1      ; print out prompt
        call    print_string

        call    read_int          ; read integer

mov  edi,input1 ;pointer to input

ask_number:
inc dword edx ;start the counter
cmp edx,21 ;does edx=21?
je end ;reached maximum size od storage space (array_size 20;))
stosb ;store value (eax only) into adress space edi(input1) by a single byte (change to stosd for dword) this instruction also increases edi to next address space automatically


mov eax, prompt2 ;add another?
call print_string

add_another:
call read_int ;read a 'y' or 'n' character, not really an int though, subsitute where necessary, possibly read_char?.

cmp eax,'y' ;did they say yes?
je ask_number ;if so jump to ask number

cmp eax,'n' ;otherwise did they say no?
jne add_another ;user did not select yes or no, repeat this again.
jmp end ; user selected no, end program.

end:
;print array as one block of numbers, by pointing to input1 but you should try to space them out as single numbers i.e. 1, 2, 3, 4, 5 rather than 12345
;if none of the calling references affect edx, then edx has the number of values stored in the simple array. inlinux you need to specify how long the message to be printed is via std-out

Hope this helps.   Looks like you are coding for windows and im on linux so not sure what your fucntions do exactly








Title: Re: array
Post by: dstudentx on February 22, 2010, 05:58:36 AM
its coding using Dr Paul Carters guidelines.
thank  you very much for the help.
I'll try to figure it out and use it

hey travman89 did you get me message?  I think I'm having problem replying.  if so send me your email.
Title: Re: array
Post by: dstudentx on February 22, 2010, 06:04:39 AM
I think I got the input of the array but now how do I output the results?
Title: Re: array
Post by: Frank Kotler on February 22, 2010, 06:58:18 AM
Well, how does it "not work at all"? Looks to me like ARAY_SIZE vs ARRAY_SIZE might be a problem. If you fix that, it'll at least assemble. Then it promptly segfaults. What could be the problem?

cmp ecx, ARRAY_SIZE -1

The "cmp" doesn't do anything without a "jcc" after it!

mov [input1 + ecx * 4], eax

What's in ecx? Random garbage! For your first, or zeroth, element, you want to start with ecx = 0, so "xor ecx, ecx" first. You'll be wanting to repeat the following code, so put a label after it.

    xor ecx, ecx
.top:

Then you go on to...

        mov     eax, prompt1      ; print out prompt
        call    print_string

        call    read_int          ; read integer
        mov     [input2], eax     ; store into input1

Well, you don't want to store it in the same place every time. Replace that with:
   
        mov [input1 + ecx * 4], eax

I guess you're done with that element. Go on to the next one.

        inc ecx

Make sure we're not done...
   
   cmp ecx, ARRAY_SIZE -1
        jna .top

Do pretty much the same thing to your output routine, and you've got a "working" program. It doesn't match the specification yet - you don't give the user a chance to quit after each element. Typing 'q' at the prompt causes the program to "go crazy". Typing "1 2 3 4 5" fills the array, with a number of redundant prompts in between. A flaw in Dr. Carter's "read_int", IMHO. Perhaps that's why he calls scanf directly, and jumps through hoops to deal with its insanity, in his array1.asm example.

As soon as you get out of this class, learn to input numbers without depending on that abomination scanf!!!

Speaking of "class"... I hope you guys realize that some schools consider getting *any* help outside of the official University help system to be "cheating". I consider it to be "cooperating to solve a problem", and I consider it to be more valuable than competing to "beat" one another, but academia doesn't see it that way, and they take it very seriously! You've been warned.

Best,
Frank

Title: Re: array
Post by: Frank Kotler on February 22, 2010, 07:59:41 AM
Hi Luke!

We can take a look at what Dr. Carter's "read_int" does...

Code: [Select]
read_int:
enter 4,0
pusha
pushf

lea eax, [ebp-4]
push eax
push dword int_format
call _scanf
pop ecx
pop ecx

popf
popa
mov eax, [ebp-4]
leave
ret

As you see, it just calls scanf, and should run on either Windows or Linux. "int_format" is just "%i", so it won't do well with 'y' or 'n'... or any other unexpected input, such as those pesky "users" are prone to do. This is a family forum, so I can't say what I think of scanf!

Dr. Carter does provide a "read_char", which will do for 'y' and 'n', and which may provide a means to replace that horrid scanf for getting a number from the user, as well. Lemme think on that...

Later,
Frank

http://www.drpaulcarter.com/pcasm to get that stuff, if you wanna play.

Title: Re: array
Post by: Frank Kotler on February 22, 2010, 09:15:02 AM
Indeed, I like this better than scanf!

Code: [Select]
;        call    read_int          ; read integer
; death to scanf!

xor ebx, ebx ; zero "result so far"
.next_char:
call read_char ; get a character in al
cmp al, 10 ; enter key
jz .got_int ; we're done with this number
cmp al, 'q'
jz .show_em ; we're done entering numbers

cmp al, '9'
ja .next_char ; simply ignore invalid digits
cmp al, '0'
jb .next_char

; we have a valid digit
; multiply result so far by 10
; and add in the digit
; subtracting '0' to convert char->number
; using lea...

lea ebx, [ebx + ebx * 4]
lea ebx, [ebx * 2 + eax - '0']

jmp .next_char

.got_int:
        mov [input1 + ecx * 4], ebx

This has still got a "flaw", in that it will allow the user to enter a number greater than will fit in 32 bits. No protection against overflow, it simple "rolls over" and returns your number "modulo 4G" - strictly speaking "correct", but probably unexpected. We could correct that with a less "clever" multiply and add - but scanf does no better.

Best,
Frank

Title: Re: array
Post by: lukus001 on February 22, 2010, 05:25:16 PM
Hi Frank,

Personally I try to avoid using other's people codes (libraries and what not) because I don't learn as much then :3  Though I'm sure the source code is readily available to read ;).

This is how I would personally do it on linux, though very primitive and limited (Stores only a byte, has no validation of numbers, does no ascii to binary conversions etc.. etc.).

Code: [Select]
section .text
global _start

_start:

;STDin
;eax, ~ system read - 3
;ebx, ~ STD-out - 1
;ecx, ~ pointer to message storage (buffer)
;edx, ~ pointer to length of buffer
;int ~ interrupt to invoke kernel - 0x80


;STDout
;eax, ~ system write - 4
;ebx, ~ STD-out - 1
;ecx, ~ pointer to message
;edx, ~ pointer to length
;int ~ interrupt to invoke kernel - 0x80

mov ebp,esp ;save stack

prompt_add_new:
mov eax,4
mov ebx,1
mov ecx,message_add_new
mov edx,lmessage_add_new
int 0x80

get_add_new:
mov eax,3
mov ebx,1
mov ecx,buffer_add_new
mov edx,lbuffer_add_new
int 0x80

cmp BYTE [ecx],'y'
je prompt_add_int
cmp BYTE [ecx],'n'
je end

prompt_wrong_value:
mov eax,4
mov ebx,1
mov ecx,message_wrong_value
mov edx,lmessage_wrong_value
int 0x80

jmp prompt_add_new

prompt_add_int:
mov eax,4
mov ebx,1
mov ecx,message_add_int
mov edx,lmessage_add_int
int 0x80

get_add_int:
mov eax,3
mov ebx,1
mov ecx,buffer_add_int
mov edx,lbuffer_add_int
int 0x80

push DWORD [ecx]
jmp prompt_add_new

end:
mov edx,ebp ;start of stack (higher value since stack grows 'down' in memory)
sub edx,esp ;start of stack minus current stack location = number of elements stored
mov ecx,edx ;ecx is used by loop as a counter,
mov edi,temp_array ;edi is our storage location for stosb/w/d use (automatically increments to next space)
mov esi,ebp ;Same as above, but used for reading values, not storing.



start_loop:
std ; Since the stack grown 'downwards' we have to set the direction flag so ESI will be drcreased, not increased
lodsd ;load Dword from location ESI into EAX. ESI will automatically change to next location hence the use of std to decrease it.
cld ;clear direction flag, becase unlike the stack, our .bss sections 'grow' so we need stosb to increase it's location value.
stosb ;store byte value of EAX (AL) in to our memory location EDI.
loop start_loop ;loop untill ECX = 0.

mov eax,10 ;add new line
stosw ;store it
add edx,1 ;edx has the original calculation for the number of element stored, unaffected by lodsb
;so add 1 to it to account for the new line we just added above, since linux wants to know length of string when
;printing to screen.



print_array:
mov eax,4
mov ebx,1
mov ecx,temp_array
;mov edx, ;already set
int 0x80

mov eax,1
int 0x80

section .text

message_add_new: db 'Would you like to add a number? y / n',10
lmessage_add_new: equ $ - message_add_new

message_wrong_value: db 'Incorrect character, please type y / n',10
lmessage_wrong_value: equ $ - message_wrong_value

message_add_int: db 'please enter your number',10
lmessage_add_int: equ $ - message_add_int

lbuffer_add_new: dd 1
lbuffer_add_int: dd 1

section .bss

buffer_add_new: resd 1
buffer_add_int: resd 1
temp_array: resb 16000
Code: [Select]
lukus001@r31773:~/development/projects/test$ ./test2
Would you like to add a number? y / n
Maybe?
Incorrect character, please type y / n
Would you like to add a number? y / n
Yes!!!! (doesn't like capital y)
Incorrect character, please type y / n
Would you like to add a number? y / n
yes (but doesnt mind additional characters)
please enter your number
1
Would you like to add a number? y / n
y
please enter your number
22
Would you like to add a number? y / n
y
please enter your number
333
Would you like to add a number? y / n
y
please enter your number
4444
Would you like to add a number? y / n
no
1234

Should be of help to dstudentx, would still need lots of editing to make it a useful array.

By the way, does anyone else find the code boxes a bit too small height wise and textwise :3??
Title: Re: array
Post by: Frank Kotler on February 23, 2010, 02:50:27 AM
I think I see a subtle error in your code...

   prompt_add_int:
   mov   eax,4
   mov   ebx,1
   mov   ecx,message_add_int
   mov   edx,lmessage_add_int

-------------------------
This is okay, 'cause "lmessage+add_int" is an equ:

   message_add_int:   db   'please enter your number',10
   lmessage_add_int: equ   $ - message_add_int   
----------------------
   int   0x80

   get_add_int:
   mov   eax,3
   mov   ebx,1
   mov   ecx,buffer_add_int
   mov   edx,lbuffer_add_int

-----------------------
In this case, "lbuffer_add_int" is a variable, with "[contents]" 1.

lbuffer_add_int:   dd   1

You're putting the address in edx! A bit more than you intend to read!
----------------------------

   int   0x80

I would point out that you're reading from STDOUT, but it turns out that this doesn't matter! You can read from STDOUT, and write to STDIN, and it works. Dunno what happens if you try to read from STDERR. Must try that...

Best,
Frank