Some hints:
# trailing \0 will write an unwanted \0 in the output
# you will give the length in the write call anyway
input1: .ascii "Input base number: \0"
# as calculated here
input1Len: .long .-input1
# you want to read those with movl (base), %eax ...
# later on !! register size is 4 bytes
# either resize or use movb (base), %al later on ...
.section .bss
.lcomm base, 1
.lcomm exponent, 1
.lcomm result, 1
#get 1st input number
movl $3, %eax
movl $1, %ebx
movl $base, %ecx
# you should give length 2 in %edx here
# ... otherwise the old value will be used
# 2 seems the right choice as it will also read the \n following
int $0x80
#write 1st input number
movl $4,%eax
movl $1,%ebx
movl $base,%ecx
# you should give length 1 in %edx here
# ... otherwise the old value will be used
int $0x80
# there's a lot of copying values back and forth
# going on here ...
# better load registers once
# => here
while:
movl (base), %eax
movl (result), %ebx
# perform your operations ...
jg while
# ... and reassign them
# => here
print:
# you'll be in big trouble here
# if anything else but
# --------------------
# base=any exponent=0
# base=0 exponent=any
# base=1 exponent=any
# base=2 exponent=0, 1, 2, 3
# base=3 exponent=0, 1, 2
# --- is given
# you'll have to calculate the decimal
# representation first ... simply adding 0x30 won't do !!
Additional hint: checking exponent for 1
and initializing result
with base
might not be the best idea. If its 0
the result
should be 1
.
EDIT: As you also asked about how to adjust the code for bigger results than 9 by properly dividing by 10 I decided to add this 2nd part.
Output of bigger numbers and division by 10
I won't go fully into details, as there already is a nice entry about that on stackoverflow (see: Assembly Language - How to Do Modulo?) but rather try to give you some brief hints.
As you already seem to have found out the main problem in outputting bigger numbers is to get the calculation of the decimal places right. Those can be calculated by a continued division by 10 using the remainder to fill in the corresponding decimal place. Example:
123 / 10 = 12 remainder 3
12 / 10 = 1 remainder 2
1 / 10 = 0 remainder 1
This algorithm stops once the result of the division reaches 0
. The decimal representation of the number is just the concatenation of the remainders. Reading upwards you get "1" . "2" . "3" = "123" which is exactly the representation you were looking for.
As explained division on the x86 can be performed by the div
instruction. The 32-bit version will read input from registers %edx
and %eax
interpreted as the 64-bit number %edx:%eax
and an additional argument. Usage of the first two registers %eax
and %edx
is implicit and can't be changed.
The result will be given as quotient in %eax
and remainder ind %edx
again this assignment is fixed.
Putting this to use in the algorithm described above seems straight forward as this are exactly the two values needed if there weren't a small complication. This complication coming in the form of giving the digits in reversed order - so by just printing them directly the would be printed like "321"
instead of "123"
for the example above.
So before being able to output the single digits you'll have to reverse their order first. The solution I chose in my attempt was to push the numbers on the stack first to write them to a string buffer in correct order while poping them from the stack again.
Example
I commented out any parts you already managed to implement in your example. The only duplicated part is the calculation process, as I'm not sure if you used the same register assigment.
.section .bss
.lcomm base, 1
.lcomm exponent, 1
.lcomm len, 4
.lcomm string, 10
# ... perform all the read operations of your example here
calculate:
# ebx: base
# ecx: exponent
# eax: result
# base
xor %ebx, %ebx
movb (base), %bl
subl $0x30, %ebx
# exponent
xor %ecx, %ecx
movb (exponent), %cl
subl $0x30, %ecx
# result
xor %eax, %eax # initilize = 0
# base == 0 ?
cmpl $0, %ebx
je prepare
movl $1, %eax # initilize = 1
while:
# exponent == 0 ?
cmpl $0, %ecx
je prepare
# multiply
imull %ebx, %eax
subl $1, %ecx
jmp while
prepare:
# eax: result
# edx: remainder
# ecx: string
# ebx: divisor
movl $0x000a, %ebx
movl %esp, %ebp
divide:
xor %edx, %edx
divl %ebx # edx:eax / ebx => q: eax mod: edx
addl $0x30, %edx
push %edx
cmpl $0, %eax
jne divide
# eax: current digit
# ebx: string buffer
# ecx: length
mov $string, %ebx
mov $0, %ecx
reverse:
pop %eax
movb %al, (%ebx, %ecx)
inc %ecx
cmp %ebp, %esp
jne reverse
mov %ecx, (len)
print:
# ... print all the other stuff of your example here
# write result
movl $4,%eax
movl $1,%ebx
movl $string, %ecx
movl (len), %edx
int $0x80