;----------------------------------------------------------------------
;read first digit
mov ah, 1d ;bios code for read a keystroke -- no error checking!
int 21h ;call bios, it is understood that the ascii code will be returned in al

mov first_num_digit_ascii, al ;may as well save a copy

sub al, 30h ;Convert code to an actual integer

cbw ;CONVERT BYTE TO WORD. This takes whatever number is in al and
;extends it to ax, boubling its size from 8 bits to 16 bits
;The first digit now occupies all of ax as an integer

mov cx, 100d ;This is so we can calculate 100*1st digit +10*2nd digit + 3rd digit
mul cx ;start to accumulate the 2 digit number in the variable imul cx ;it is understood that the other operand is ax
;AND that the result will use both dx::ax
;but we understand that dx will contain only leading zeros
add number1, ax ;save

;variable <number1> now contains 1st digit * 10
;----------------------------------------------------------------------
;read second digit, multiply by 10 and add in
mov ah, 1d ;bios code for read a keystroke -- no error checking!
int 21h ;call bios, it is understood that the ascii code will be returned in al

mov first_num_digit2_ascii, al ;may as well save a copy

sub al, 30h ;Convert code to an actual integer

cbw ;CONVERT BYTE TO WORD. This takes whatever number is in al and
;extends it to ax, boubling its size from 8 bits to 16 bits
;The first digit now occupies all of ax as an integer

mov cx, 10d ;continue to accumulate the 3 digit number in the variable
mul cx ;it is understood that the other operand is ax, containing first digit
;AND that the result will use both dx::ax
;but we understand that dx will contain only leading zeros. Ignore them
add number1, ax ;save -- nearly finished
;variable <number1> now contains 1st digit * 100 + second digit * 10
;----------------------------------------------------------------------

;----------------------------------------------------------------------
;read first digit for second number
mov ah, 1d ;bios code for read a keystroke -- no error checking!
int 21h ;call bios, it is understood that the ascii code will be returned in al

mov second_num_digit_ascii, al ;may as well save a copy

sub al, 30h ;Convert code to an actual integer

cbw ;CONVERT BYTE TO WORD. This takes whatever number is in al and
;extends it to ax, boubling its size from 8 bits to 16 bits
;The first digit now occupies all of ax as an integer

mov cx, 100d ;This is so we can calculate 100*1st digit +10*2nd digit + 3rd digit
mul cx ;start to accumulate the 3 digit number in the variable imul cx ;it is understood that the other operand is ax
;AND that the result will use both dx::ax
;but we understand that dx will contain only leading zeros
add number2, ax ;save

;variable <number2> now contains 1st digit * 10
;----------------------------------------------------------------------
;read second digit for second number, multiply by 10 and add in
mov ah, 1d ;bios code for read a keystroke -- no error checking!
int 21h ;call bios, it is understood that the ascii code will be returned in al

mov second_num_digit2_ascii, al ;may as well save a copy

sub al, 30h ;Convert code to an actual integer

cbw ;CONVERT BYTE TO WORD. This takes whatever number is in al and
;extends it to ax, boubling its size from 8 bits to 16 bits
;The first digit now occupies all of ax as an integer

mov cx, 10d ;continue to accumulate the 3 digit number in the variable
mul cx ;it is understood that the other operand is ax, containing first digit
;AND that the result will use both dx::ax
;but we understand that dx will contain only leading zeros. Ignore them
add number2, ax ;save -- nearly finished
;variable <number2> now contains 1st digit * 100 + second digit * 10
;----------------------------------------------------------------------

;now print the digits
mov ah, 2d ;bios code for print a character
mov dl, second_num_digit_ascii ;we had saved the ascii code here
;code must be in dl
int 21h ;call to bios

mov ah, 2d ;bios code for print a character
mov dl, second_num_digit2_ascii ;we had saved the ascii code here
;code must be in dl
int 21h ;call to bios

;we have our two numbers saved in the variables number1 and number2ax
;save number1 into ax and number2 into bx
;now we move on to our loop to find the greatest common factor

mov ax,number1
mov bx,number2

jnz Loop1

Loop1:
cmp ax,bx ;compares the two values
jz Loop3 ;Their equal so it jumps to Loop3 and ends
cmp ax,bx ;the two numbers are not the same so we move on
jg Loop2 ;if ax > bx then it jumps to Loop2
;If we're still in this loop then ax < bx
sub bx,ax ;Subtracts bx by ax
jmp Loop1 ;repeats around until equal

Loop2:
;To get here then that means ax > bx, then we must lower ax
sub ax, bx
jmp Loop1 ;goes back to Loop1 until they become equal

The program was written for tasm, I made a few changes to the code, i'll post that below. The problem I'm having is printing the result of the loop which is stored in ax, after the loop ends.The output i'm getting is the characters "T" "O" rather than a number.

Here is the edited code:

Code:

.model small
.stack 400h
.data
first_num_digit_ascii db ?
first_num_digit2_ascii db ?
second_num_digit_ascii db ?
second_num_digit2_ascii db ?
prompt1 db 0ah,0dh,'Please enter the first number: $'
prompt2 db 0ah,0dh,'Please enter the second number: $'
prompt3 db 0ah,0dh,'The highest common factor is: $'
confirmation_string db 0ah,0dh,'You typed ---> $'
number1 dw 0d
number2 dw 0d
gcf dw 0d
.code
mov ax, @data ;establish access to the data segment
mov ds, ax ;of memory
mov number1, 0d ;just to be sure
mov ax, @data
mov ds,ax
mov ah,9d
mov dx, offset prompt1 ;print prompt for first number
int 21h
;----------------------------------------------------------------------
;read first digit
mov ah, 1d ;bios code for read a keystroke -- no error checking!
int 21h ;call bios, it is understood that the ascii code will be returned in al
mov first_num_digit_ascii, al ;may as well save a copy
sub al, 30h ;Convert code to an actual integer
cbw ;CONVERT BYTE TO WORD. This takes whatever number is in al and
;extends it to ax, boubling its size from 8 bits to 16 bits
;The first digit now occupies all of ax as an integer
mov cx, 100d ;This is so we can calculate 100*1st digit +10*2nd digit
mul cx ;start to accumulate the 2 digit number in the variable imul cx ;it is understood that the other operand is ax
;AND that the result will use both dx::ax
;but we understand that dx will contain only leading zeros
add number1, ax ;save
;variable <number1> now contains 1st digit * 10
;----------------------------------------------------------------------
;read second digit, multiply by 10 and add in
mov ah, 1d ;bios code for read a keystroke -- no error checking!
int 21h ;call bios, it is understood that the ascii code will be returned in al
mov first_num_digit2_ascii, al ;may as well save a copy
sub al, 30h ;Convert code to an actual integer
cbw ;CONVERT BYTE TO WORD. This takes whatever number is in al and
;extends it to ax, boubling its size from 8 bits to 16 bits
;The first digit now occupies all of ax as an integer
mov cx, 10d ;continue to accumulate the 2 digit number in the variable
mul cx ;it is understood that the other operand is ax, containing first digit
;AND that the result will use both dx::ax
;but we understand that dx will contain only leading zeros. Ignore them
add number1, ax ;save -- nearly finished
;variable <number1> now contains 1st digit * 100 + second digit * 10
;----------------------------------------------------------------------
;proof of conversion
mov ah, 9d ;bios code for print a dollar delimited string
mov dx, offset confirmation_string ;address of 1st character is ds::dx
int 21h ;Do the output, printing You typed --->
;now print the digits
mov ah, 2d ;bios code for print a character
mov dl, first_num_digit_ascii ;we had saved the ascii code here
;code must be in dl
int 21h ;call to bios
mov ah, 2d ;bios code for print a character
mov dl, first_num_digit2_ascii ;we had saved the ascii code here
;code must be in dl
int 21h ;call to bios
jnz Second_digit
;------------------------------------------------------------------------
Second_digit:
mov ax, @data ;establish access to the data segment
mov ds, ax ;of memory
mov number2, 0d ;just to be sure
mov ax, @data
mov ds,ax
mov ah,9d
mov dx, offset prompt2 ;print prompt for the second number
int 21h
;----------------------------------------------------------------------
;read first digit for second number
mov ah, 1d ;bios code for read a keystroke -- no error checking!
int 21h ;call bios, it is understood that the ascii code will be returned in al
mov second_num_digit_ascii, al ;may as well save a copy
sub al, 30h ;Convert code to an actual integer
cbw ;CONVERT BYTE TO WORD. This takes whatever number is in al and
;extends it to ax, boubling its size from 8 bits to 16 bits
;The first digit now occupies all of ax as an integer
mov cx, 100d ;This is so we can calculate 100*1st digit +10*2nd digit
mul cx ;start to accumulate the 2 digit number in the variable imul cx
;it is understood that the other operand is ax
;AND that the result will use both dx::ax
;but we understand that dx will contain only leading zeros
add number2, ax ;save
;variable <number2> now contains 1st digit * 10
;----------------------------------------------------------------------
;read second digit for second number, multiply by 10 and add in
mov ah, 1d ;bios code for read a keystroke -- no error checking!
int 21h ;call bios, it is understood that the ascii code will be returned in al
mov second_num_digit2_ascii, al ;may as well save a copy
sub al, 30h ;Convert code to an actual integer
cbw ;CONVERT BYTE TO WORD. This takes whatever number is in al and
;extends it to ax, boubling its size from 8 bits to 16 bits
;The first digit now occupies all of ax as an integer
mov cx, 10d ;continue to accumulate the 2 digit number in the variable
mul cx ;it is understood that the other operand is ax, containing first digit
;AND that the result will use both dx::ax
;but we understand that dx will contain only leading zeros. Ignore them
add number2, ax ;save -- nearly finished
;variable <number2> now contains 1st digit * 100 + second digit * 10
;----------------------------------------------------------------------
;proof of conversion
mov ah, 9d ;bios code for print a dollar delimited string
mov dx, offset confirmation_string ;address of 1st character is ds::dx
int 21h ;Do the output, printing You typed --->
;now print the digits
mov ah, 2d ;bios code for print a character
mov dl, second_num_digit_ascii ;we had saved the ascii code here
;code must be in dl
int 21h ;call to bios
mov ah, 2d ;bios code for print a character
mov dl, second_num_digit2_ascii ;we had saved the ascii code here
;code must be in dl
int 21h ;call to bios
;we have our two numbers saved in the variables number1 and number2
;save number1 into ax and number2 into bx
;now we move on to our loop to find the greatest common factor
mov ax,number1
mov bx,number2
jnz Loop1
Loop1:
cmp ax,bx ;compares the two values
jz Print ;Their equal so it jumps to Print and ends
cmp ax,bx ;the two numbers are not the same so we move on
jg Loop2 ;if ax > bx then it jumps to Loop2
;If we're still in this loop then ax < bx
sub bx,ax ;Subtracts bx by ax
jmp Loop1 ;repeats around until equal
Loop2:
;To get here then that means ax > bx, then we must lower ax
sub ax,bx
jmp Loop1 ;goes back to Loop1 until they become equal
Print:
;The two values are equal and it comes here and prints
mov dx, offset prompt3
mov ah, 9d ;BIOS code for print a string
int 21h
mov gcf,ax ;save answer from ax to variable gcf
mov dx,0d ;clear dx register before dividing
mov cx,10d ;add 10 to cx and divide
div cx
mov bx,0d ;clear bx register
mov bx,dx ;remainder is left in dx, move remainder to bx
add bl,30h ;convert to ascii
mov dx,gcf ;put gcf value into dx register
add dl,30h ;convert to ascii
mov ah,2d ;print first digit
int 21h
mov dx,bx ;bx holds the second digit of the answer
mov ah,2d ;move it into dx and print
int 21h
jnz skip_message ;jump to exit program
skip_message:
;exit gracefully
mov ah, 4ch
int 21h
end

Is TASM required for the class your taking or the book you're using? Just wondering, because it's rather old now (last version, 5.0, was released in 1996) and AFAIK it was never released to the public domain (nor was it sold separately). Also, do you know which version you're using?

EDIT: I managed to scratch up a copy of Turbo Assembler 5.0, and assembled the program as given. It assembled without errors, but TLINK couldn't find the start of the program with which to link it to an executable - the error message I got was

Code:

Fatal: No program entry point

- which implies that this listing wasn't a complete program. Was there more code than you've shown?

Continued: Apparently, you need a label named 'start' at the beginning of the code segment to make the program work correctly with TASM v.5.0 . I was able to run it, with this result:

Code:

Please enter the first number: 12
You typed ---> 12
Please enter the second number: 3
You typed ---> 3
The highest common factor is: :
Thank you! Have a nice day.

Now, I have to admit that this isn't the best assembly code I've seen, and I am much more familiar with Netwide Assembler, so I'm having some trouble following it. I'll get back to you about what I find as soon as I am able.

Thank you for your help =) I know my assembly code isn't the best, but I finally figured the problem out! Tasm was required for this assignment, so I had no other choice, and I must have been running an older version of tasm.

As it happens, you may be doing better than I did with it; I had tried to re-write the program (using the more familiar NASM) according to what I consider 'good' assembly language practices, and I ended up making a botch of it. For what it's worth, here's my version:

As you can see, it isn't really adequately commented, though I did at least replace a lot of magic numbers with named constants. The real problem is that I couldn't get the GCD subroutine to work right; it sometimes causes the program to loop back to the start, while at other times causes a protection fault. Given that this was meant to help you, I doubt it's worth my while to quite finish seeing how you got your version working yesterday...

While I corrected the underlying issue with the GCD function causing a crash (it was a silly error in stack handling), I still can't seem to get it to work. It is frustrating me to no end, which is really odd since it isn't even my assignment. Go figure... anyway, I'd appreciate any advice anyone can give, as I continue working on it.

The "mov dx, 0" instruction in gcd has to move inside of the fake_recurse loop. Otherwise the remainder from the last iteration is taken as the high bits of the divisor.

At the risk of thread necromancy, I should mention that on revisiting the code, I realized that I was declaring the RESW as size 0; this meant that I was overwriting number1 with number2. Fixing this solved that issue, but caused the program to have a divide overflow whenever BX was larger than AX. Testing the operands and exchanging them when that occurred only resulted in the program hanging. Thus, this simple program is still frustrating me.EDIT: I finally got it working; I somehow had undone the change OZ recommended. Here is the final working version:

popl %edi
popl %esi
ret
.a_zero:
movl %ecx, %eax
ret
.b_zero:
movl 4(%esp), %eax
ret[/code]The code is a bit longer because it has to reduce to the case where both numbers are odd before executing the main loop. The main loop itself is pretty slim. As you can see, I did not implement any I/O in assembly; the driver modules are written in C. Here they are: [code=gcd-test.c]#include <stdio.h>
#include <stdlib.h>