ProgrammingThis 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.
I'm trying to get simple assembly program to do some small calculation and to print the result. Currently it goes through the assembler and linker without errors or warnings but it won't print anything and seems to exit with failure (1).
Also the debugging doesn't seem to work as it won't assign the break points.
Whats going on and how can I proceed with this?
Code:
.section .text
.global _start
# The calculation
# 1444x = 1024x + 256x + 128x + 32x + 4x
_start:
xorl %eax, %eax # set eax to 0
movw $2, %bx # variable to multiply (X)
movw %bx, %ax # X
shl $10, %ax # *1024
pushw %ax # stack (1)
movw %bx, %ax # X
shl $8, %ax # *256
pushw %ax # stack (2)
movw %bx, %ax # X
shl $7, %ax # *128
pushw %ax # stack (3)
movw %bx, %ax # X
shl $5, %ax # *32
pushw %ax # stack (4)
movw %bx, %ax # X
shl $2, %ax # *4
pushw %ax # stack (5)
popw %bx # stack (4)
addw %bx, %ax # +4X
popw %bx # stack (3)
addw %bx, %ax # +32X
popw %bx # stack (2)
addw %bx, %ax # +128X
popw %bx # stack (1)
addw %bx, %ax # +256X
popw %bx # stack (0)
addw %bx, %ax # +1024X
movl %eax, %ecx # store result for printing
movl $4, %eax # syscall to use (write)
movl $1, %ebx # fd of result 1 = stdout
movl $4, %edx # How much to read, 4 bytes
int $0x80 # call the kernel
movl $1, %eax # syscall ( 1 = exit )
xorl %ebx, %ebx # (exit value)
int $0x80 # call the kernel
ret
Here's the stuff when I try to run and debug the above.
Code:
zmyrgel@cube zmyrgel-> as -gstabs -o stack.o stack.s
zmyrgel@cube zmyrgel-> ld -o stack stack.o
zmyrgel@cube zmyrgel-> ./stack
zmyrgel@cube zmyrgel-> gdb stack
GNU gdb 6.8
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-pc-linux-gnu"...
(gdb) l
1 .section .text
2 .global _start
3
4 # The calculation
5 # 1444x = 1024x + 256x + 128x + 32x + 4x
6 _start:
7 xorl %eax, %eax # set eax to 0
8 movw $2, %bx # variable to multiply (X)
9
10 movw %bx, %ax # X
(gdb) b 1
Breakpoint 1 at 0x8048054: file stack.s, line 1.
(gdb) r
Starting program: /home/zmyrgel/stack
Program exited with code 01.
(gdb) q
zmyrgel@cube zmyrgel->
Last edited by Zmyrgel; 03-04-2009 at 11:27 AM.
Reason: updated the code
This line doesn't translate into executable code, try break 7 or even break _start.
The problem with your program is that sys_write expects a char* (pointer to byte) representing a string. You are passing a number which will be interpreted as a pointer (probably an address that your program doesn't own). I think it would be easier if you call your assembly function from C and print the result using the C library.
Code:
################
# assemby file
################
.section .text
.global calculation
# The calculation
# 1444x = 1024x + 256x + 128x + 32x + 4x
calculation:
# save the callee-save registers on the stack
push %ebp
push %ebx
push %edi
push %esi
push %edi
# calculation code, put result in %eax...
# restore callee-save registers
pop %edi
pop %esi
pop %edi
pop %ebx
pop %ebp
ret
Code:
/*********
* C file
*********/
#include <stdio.h>
int calculation(); /* defined in assembly file */
int main()
{
int result = calculation();
printf("calculation() = %d\n", result);
return 0;
}
Last edited by ntubski; 03-04-2009 at 02:15 PM.
Reason: separate C and asm
This line doesn't translate into executable code, try break 7 or even break _start.
I tried it but it gave same result.
Quote:
Originally Posted by ntubski
The problem with your program is that sys_write expects a char* (pointer to byte) representing a string. You are passing a number which will be interpreted as a pointer (probably an address that your program doesn't own). I think it would be easier if you call your assembly function from C and print the result using the C library.
Unfortunately that isn't an option. At least not yet. This is assembly programming course homework and it needs to be assembly. The calculation with stack is the main idea. I just wanted to have it print the result too but its quite difficult. Good point on the pointer issue. I'm not sure how to do it in assembly. I've read lot of tutorials that use write call with predefined 'hello world' string but I don't know how mimic that in my program.
This is assembly programming course homework and it needs to be assembly.
That's a rotten way to teach assembly.
A beginner will get so bogged down in the inability to do I/O that it will interfere with learning anything interesting.
Beginning assembly (and most of the time, even advanced assembly) should be taught as writing subroutines to be called by an instructor provided main program.
But that is all in your instructor's control, not your control.
Quote:
I just wanted to have it print the result too but its quite difficult.
Do you know the basic concepts of converting a number to base ten text (described below in case you don't)? Coding that in assembler is a useful beginner exercise, so give it a try.
Generate the digits right to left in a (bottom checked) loop:
At each step divide the working value by 10 producing both a quotient (which becomes the new working value) and a remainder, which is added to the ascii code of '0' to produce the next digit (right to left).
Loop until the working value is zero.
You'll need some thought on where/how to store the digits as you create them right to left. But that still should be in the range of beginning assembler.
A beginner will get so bogged down in the inability to do I/O that it will interfere with learning anything interesting.
Beginning assembly (and most of the time, even advanced assembly) should be taught as writing subroutines to be called by an instructor provided main program.
Yeah, I think later in the course we start to use C too.
Quote:
Originally Posted by johnsfine
Do you know the basic concepts of converting a number to base ten text?
You mean converting base ten value to binary or what? Number -> text conversion seems pretty odd consept at these alcohol levels
I removed the printing of the number from the code and used debugger on it. I fixed the small thing that I didn't set the eax to 0 after last placement in the stack... I could have kept the value in the register too but I chose the former way for now.
You mean converting base ten value to binary or what?
No the opposite: Converting a number from the internal form used by the computer (calling that "binary" can cause confusion I wanted to avoid) to base ten.
Some mixed C and psuedo code:
Code:
int work = the number to convert;
char* pointer = the buffer address plus the length of the buffer;
do { // bottom checked loop
int remainder = work % 10;
work = work / 10;
*(--pointer) = remainder + '0';
} while ( work != 0 )
pointer now points at the text to print but you need to compute the length;
int length=buffer address plus length of buffer minus pointer;
Now, just code the same thing in assembler and add it to what you've coded so far.
Quote:
seems pretty odd consept at these alcohol levels
I could get that bit of code right while drunk, but I don't test that very often. I'll just hope you were joking.
No the opposite: Converting a number from the internal form used by the computer (calling that "binary" can cause confusion I wanted to avoid) to base ten.
Yeah, sorry. Mixed those already. What do you mean by 'case confusion'? I thought computers used binary... or rather electric currents to do stuff internally.
Quote:
Originally Posted by johnsfine
I could get that bit of code right while drunk, but I don't test that very often. I'll just hope you were joking.
Nah, not drunk. Just a little tipsy... or I was a little while ago. Now I'm just getting sleepy, should be at school in 7 hours so I'd better go get some Z's before that.
What do you mean by 'case confusion'? I thought computers used binary.
Computers do use binary, but that fact is not relevant to programming (even in assembly language) as often as you might expect.
When you are converting input or output from or to some base, the fact that the computer uses binary isn't very relevant but can be very confusing.
If I want to input a number in binary, I need code to convert that number from base 2 (binary) to internal form. If I confuse myself by calling internal form "binary", that is a converter from binary to binary.
When you code an assembly language instruction to add, subtract, multiply, divide, etc. the numbers in two registers, you should normally think of that just as add, subtract, multiply or divide of those numbers, not of those binary numbers.
There are various overflow issues where it is important to pay more attention to the way the number is really stored. But even then, it can be easier to think about, and just as well connected to the underlying reality, if you think a register holds an 8 digit base 16 number, rather than a 32 digit base 2 number.
If I want to input a number in binary, I need code to convert that number from base 2 (binary) to internal form. If I confuse myself by calling internal form "binary", that is a converter from binary to binary.
When you code an assembly language instruction to add, subtract, multiply, divide, etc. the numbers in two registers, you should normally think of that just as add, subtract, multiply or divide of those numbers, not of those binary numbers.
There are various overflow issues where it is important to pay more attention to the way the number is really stored. But even then, it can be easier to think about, and just as well connected to the underlying reality, if you think a register holds an 8 digit base 16 number, rather than a 32 digit base 2 number.
oops, I didn't test that first, it seems to work with break 8, I don't understand why...
I think johnsfine's point is that you have to be careful not to confuse a binary string (eg "101010"), with the internal storage format. Everything is stored as bytes internally, what the bytes mean depends on how you use them. In gdb you can decide which format to print values in:
Then just to figure out the fundamental thing on the next asm assignment ... and to convert it to work on my Linux machine as I highly doubt the DOS system calls will work on it
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.