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 |
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
Are you new to LinuxQuestions.org? Visit the following links:
Site Howto |
Site FAQ |
Sitemap |
Register Now
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
 |
GNU/Linux Basic Guide
This 255-page guide will provide you with the keys to understand the philosophy of free software, teach you how to use and handle it, and give you the tools required to move easily in the world of GNU/Linux. Many users and administrators will be taking their first steps with this GNU/Linux Basic guide and it will show you how to approach and solve the problems you encounter.
Click Here to receive this Complete Guide absolutely free. |
|
 |
01-31-2008, 10:18 PM
|
#1
|
|
Member
Registered: Jun 2004
Location: Inland NW, US
Distribution: Ubuntu
Posts: 362
Rep:
|
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.
|
|
|
|
02-01-2008, 12:13 AM
|
#2
|
|
Senior Member
Registered: Sep 2003
Posts: 3,171
Rep: 
|
Quote:
Originally Posted by jrtayloriv
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.
|
|
|
|
02-01-2008, 01:52 AM
|
#3
|
|
Member
Registered: Jun 2004
Location: Inland NW, US
Distribution: Ubuntu
Posts: 362
Original Poster
Rep:
|
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.
|
|
|
|
02-01-2008, 07:48 AM
|
#4
|
|
Member
Registered: Nov 2006
Posts: 344
Rep:
|
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! 
|
|
|
|
02-01-2008, 08:06 AM
|
#5
|
|
Member
Registered: Jun 2004
Location: Inland NW, US
Distribution: Ubuntu
Posts: 362
Original Poster
Rep:
|
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
|
|
|
|
02-01-2008, 08:16 AM
|
#6
|
|
Member
Registered: Nov 2006
Posts: 344
Rep:
|
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... 
|
|
|
|
02-01-2008, 08:35 AM
|
#7
|
|
Member
Registered: Jun 2004
Location: Inland NW, US
Distribution: Ubuntu
Posts: 362
Original Poster
Rep:
|
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.
|
|
|
|
02-01-2008, 08:46 AM
|
#8
|
|
Member
Registered: Jun 2004
Location: Inland NW, US
Distribution: Ubuntu
Posts: 362
Original Poster
Rep:
|
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.
|
|
|
|
| Thread Tools |
Search this Thread |
|
|
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -5. The time now is 09:20 AM.
|
|
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.
|
Latest Threads
LQ News
|
|