LinuxQuestions.org
Support LQ: Use code LQ3 and save $3 on Domain Registration
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 01-31-2008, 10:18 PM   #1
jrtayloriv
Member
 
Registered: Jun 2004
Location: Inland NW, US
Distribution: Ubuntu
Posts: 365
Blog Entries: 1

Rep: Reputation: 44
x86 assembly -- problem w/ syntax for looping over array


I am trying to run the following x86 assembly code, which is meant to add a set of numbers up and print out the result:

Code:
.section .data   

   message:      
      .ascii "The sum of the first 5 primes is \0"

   numbers:
     .long 2, 3, 5, 7, 11

.section .text

.globl _start

_start:

####################
# Print our message#
####################

    movl $0, %edi                   # set index pointer to 0
    movl $4, %eax                   # syscall -- write()
    movl $1, %ebx                   # file descriptor '1' (STDOUT)
    movl $message, %ecx             # put start address of string in %ecx
    movl $35,%edx                   # string is 35 chars long
    int  $0x80                      # interrupt 80 -- Linux syscall

######################
# Add the numbers up #
######################

# %edi will hold our current position
# %ecx will hold the counter
# %edx will hold the current sum

    movl $0, %edi                   # start at the first byte 0
    movl $0, %edx                   # initialize sum variable to 0
    movl $5, %ecx                   # set counter to 5 (because we have 5 numbers)
 
add_loop:
    cmpl $0, %ecx                   # check to see if the counter is 0 yet
    je print_sum                    # if so, we're done, so print the result
                                    # otherwise, continue adding the numbers
    addl $numbers(,%edi,4), %edx    # add the next element to the sum in %edx
    subl $1, %ecx                   # decrement the counter
    jmp add_loop		    # go back to the top of the loop

print_sum:
    movl $4, %eax                   # syscall -- write()
    movl $1, %ebx                   # file descriptor '1' (STDOUT)
    pushl %edx
    movl %esp, %ecx                 # put start address of string in %ecx
    movl $4, %edx                   # we're printing a 4 byte string
    int  $0x80                      # interrupt 80 -- Linux syscall

################
# Exit Program #
################

    movl $1, %eax                   # syscall -- exit()
    movl $0, %ebx                   # return (0)
    int  $0x80                      # interrupt 80 -- Linux syscall
My first problem is with the line addl $numbers(,%edi,4), %edx in the add_loop. This is obviously not syntactically correct, as I am getting an error trying to assemble it. I was trying to copy the syntax from a movl instruction that was shown earlier in the book I am reading, but obviously this does not work. How would I got about telling it to go through each of the numbers in $numbers and add 4 to %edi (i.e. move up 4 bytes to the next number)?

My second problem concerns the print_sum statement. Is this the correct way to push the sum held in %edx to the stack and then print it?

Any other suggestions on better assembly programming practices would be appreciated as well.

Thanks,
jrtayloriv

Last edited by jrtayloriv; 01-31-2008 at 10:19 PM.
 
Old 02-01-2008, 12:13 AM   #2
jiml8
Senior Member
 
Registered: Sep 2003
Posts: 3,171

Rep: Reputation: 114Reputation: 114
Quote:
Originally Posted by jrtayloriv View Post
My first problem is with the line addl $numbers(,%edi,4), %edx in the add_loop. This is obviously not syntactically correct, as I am getting an error trying to assemble it.
Try addl $numbers,(%edi,4),%edx

Quote:
My second problem concerns the print_sum statement. Is this the correct way to push the sum held in %edx to the stack and then print it?
I'll pass on this. I don't see anything wrong with it, but I would have to have a truly compelling reason to do this in assembler rather than C (or in a shell script, for that matter), so I am not up on the details of setting registers for linux system calls at that level.
[/QUOTE]

Last edited by jiml8; 02-01-2008 at 12:15 AM.
 
Old 02-01-2008, 01:52 AM   #3
jrtayloriv
Member
 
Registered: Jun 2004
Location: Inland NW, US
Distribution: Ubuntu
Posts: 365
Blog Entries: 1

Original Poster
Rep: Reputation: 44
Quote:
Try addl $numbers,(%edi,4),%edx
That didn't work -- when I did that, I got an error message stating:
Code:
test.s: Assembler messages:
test.s:60: Warning: scale factor of 4 without an index register
test.s:60: Error: suffix or operands invalid for `add'
addl only takes two operands, so wouldn't the way you recommended be giving it three? I'm assuming that's why the 'suffix or operands invalid' error is popping up. Or am I misunderstanding something about the syntax? Does the comma operator not work like in other languages?

I double-checked the book, and the way I had it was how the book mentioned it. I had figured that maybe the space before the comma that was inside the parentheses in $numbers(,%edi,4) was maybe defaulting to something like $numbers(DEFAULT_VALUE,%edi,4) ... was I wrong there? Was there a typo in the book?

Like I said before though, they were using movl on the list of numbers, not addl -- is there a different method for addl? How would I tell it to walk through the list of numbers here? Was I at least on the right track?

Quote:
I don't see anything wrong with it, but I would have to have a truly compelling reason to do this in assembler rather than C (or in a shell script, for that matter), so I am not up on the details of setting registers for linux system calls at that level.
I realize that this is not something that one would normally do in assembler -- but I am trying to learn assembler right now, and I can't just jump right into writing device drivers

Thanks,
jrtayloriv

Last edited by jrtayloriv; 02-01-2008 at 02:18 AM.
 
Old 02-01-2008, 07:48 AM   #4
Dox Systems - Brian
Member
 
Registered: Nov 2006
Posts: 344

Rep: Reputation: 31
What assembler are you using? The syntax is quite a bit different from what I'm used to (MASM/TASM). I don't have my processor guide with me right now (and haven't seriously done asm in a few years), but I would do something like this to start with in MASM/TASM:

add dword ptr offset numbers[edi*4], edx

Actually, looking at that, something may be wrong. Can a scale be applied to an index, or only a base register? Hmmm, sure wish I was at home where my processor guide is!
 
Old 02-01-2008, 08:06 AM   #5
jrtayloriv
Member
 
Registered: Jun 2004
Location: Inland NW, US
Distribution: Ubuntu
Posts: 365
Blog Entries: 1

Original Poster
Rep: Reputation: 44
Thanks for the response Brian.

Quote:
What assembler are you using? The syntax is quite a bit different from what I'm used to (MASM/TASM)
I am using the 'AT&T' syntax that gas, gcc, && gdb use.


I did a bit more reading, and I found this:

Quote:

The general form of memory address references is this:

ADDRESS_OR_OFFSET(%BASE_OR_OFFSET,%INDEX,MULTIPLIER)

(...)

indexed addressing mode:

This is done by using the ADDRESS_OR_OFFSET and the %INDEX portion. You can use any general-purpose register as the index register. You can also have a constant multiplier of 1, 2, or 4 for the index register, to make it easier to index by bytes, double-bytes, and words. For example, let's say that we had a string of bytes as string_start and wanted to access the third one (an index of 2 since we start counting the index at zero), and %ecx held the value 2. If you wanted to load it into %eax you could do the following:

movl string_start(,%ecx,1), %eax
But I can't figure out what exactly I'm doing wrong. I must not be understanding some basic concept about what's happening. Any ideas?

Thanks,
jrtayloriv
 
Old 02-01-2008, 08:16 AM   #6
Dox Systems - Brian
Member
 
Registered: Nov 2006
Posts: 344

Rep: Reputation: 31
AT&T syntax, which is the destination, the first or second operand?

IIRC, you can't add directly to a memory location (read from, calculate, then write to a location). Once again, wish my processor book was here though...
 
Old 02-01-2008, 08:35 AM   #7
jrtayloriv
Member
 
Registered: Jun 2004
Location: Inland NW, US
Distribution: Ubuntu
Posts: 365
Blog Entries: 1

Original Poster
Rep: Reputation: 44
Brian --

In AT&T syntax it is ADD SRC, DEST

I'm making progress. I have rewritten the section that does the adding as follows:

Code:
    movl $0, %edx                   # initialize sum variable to 0
    movl $5, %ecx                   # set counter to 5 (because we have 5 numbers)
    movl $numbers, %eax             # move address of $numbers into %eax

add_loop:
    cmpl $0, %ecx                   # check to see if the counter is 0 yet
    je print_sum                    # if so, we're done, so print the result
                                    # otherwise, continue adding the numbers
    addl (%eax), %edx               # add the next element to the sum in %edx
    subl $1, %ecx                   # decrement the counter
    addl $4, %eax                   # point %eax to the next number in the list
    jmp add_loop                    # go back to the top of the loop
And just for debugging purposes, I went ahead and just made the program exit with the sum stored in %edx as the return value (which I can retrieve w/ echo $?)

So now the program just goes jumps to this, after the counter is decremented to zero:

Code:
print_sum:

    movl $1, %eax                   # syscall -- exit()
    movl (%edx), %ebx               # return value in %edx to caller -- i.e. shell
    int  $0x80                      # interrupt 80 -- Linux syscall
And I went into gdb, set a breakpoint at the print_sum function, and did a dump of the registers:

Code:
eax            0x804918a        134517130
ecx            0x0      0
edx            0x1c     28
ebx            0x1      1
esp            0xbe12d5b0       0xbe12d5b0
ebp            0x0      0x0
esi            0x0      0
edi            0x0      0
eip            0x80480f9        0x80480f9 <print_sum>
eflags         0x246    [ PF ZF IF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x0      0
As you can see, %edx holds the correct sum. However, I'm getting a segfault now:

Code:
TThe sum of the first 5 primes is Segmentation fault
(Note the two 'T's .... hmmmm?)

Any ideas why this might be happening?

--jrtayloriv

Last edited by jrtayloriv; 02-01-2008 at 08:41 AM.
 
Old 02-01-2008, 08:46 AM   #8
jrtayloriv
Member
 
Registered: Jun 2004
Location: Inland NW, US
Distribution: Ubuntu
Posts: 365
Blog Entries: 1

Original Poster
Rep: Reputation: 44
Bingo!

That was silly

I was telling it to use the value in %edx as an address in print_sum (The parentheses are like deferencing a pointer). I just had to change:

movl (%edx), %ebx

to

movl %edx, %ebx


But I still can't figure out why it's printing two 'T's. And now that I fixed the add_loop, I'd like to figure out how to actually print out the value in %edx to stdout, rather than having to check the return status.

The write() syscall is using up all of my general purpose registers, so I guess I'll have to figure out how to store something into a variable -- but I haven't gotten that far yet in the book ...

--jrtayloriv

Last edited by jrtayloriv; 02-01-2008 at 09:12 AM.
 
  


Reply

Tags
array, assembly, loop, x86


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
bash syntax: looping through a comma-separated list David the H. Linux - General 10 09-06-2007 10:23 AM
Assembly Language syntax ashlesha Linux - Newbie 4 06-30-2006 04:22 PM
x86 assembly programming in Linux XsuX Programming 9 12-01-2004 09:45 AM
perl - simple array syntax problem lrt2003 Programming 3 05-09-2004 01:35 PM
Assembly syntax jinksys Programming 1 09-01-2003 05:07 PM


All times are GMT -5. The time now is 01:09 PM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration