I'm currently struggling in outputting AzByCx in ms debug since I don't really know too much about it.
Included here are the Basic commands that my teacher sent to us.
I can output A-Z easily, but not AzBxCy, there's not much of a detailed tutorial online so I came here to ask.
-e 200 "Az"
-a
1BD8:0100 mov bx, word [200]
1BD8:0104 mov cx, 3
1BD8:0107 mov ah, 2
1BD8:0109 mov dl, bl
1BD8:010B int 21
1BD8:010D mov dl, bh
1BD8:010F int 21
1BD8:0111 add bx, FF01
1BD8:0115 loop 109
1BD8:0117 mov dl, 0D
1BD8:0119 int 21
1BD8:011B mov dl, 0A
1BD8:011D int 21
1BD8:011F mov ax, 4C00
1BD8:0122 int 21
1BD8:0124
-g
AzByCx
What does this do?
initialises word at ds:200h to the string "Az" (little endian low byte is "A", high byte is "z")
use A command to assemble the following program:
load from memory into register bx (to initialise the register without having to look up the numeric ASCII codepoints)
set up cx as loop counter for three iterations
set up register ah for the interrupt 21h service 02h (display character in dl)
display character read from bl (low byte of bx)
display character from bh (high byte of bx)
add 1 to bl and -1 (in two's complement resulting in 0FFh) to bh which increments the codepoint in bl and decrements the one in bh
loop back to display subsequent letters
display a linebreak (codepoints 13 and 10, or 0Dh 0Ah) to make the output easier to read
terminate program
use G command to run the program
Microsoft DEBUG.EXE can indeed be used to write a simple program in Intel-syntax assembly, see this example. Replace the string definition db "Hello world$" with db "AzByCx$" and you're done.
However, this is definitely not a good way how to learn assembly language.
Find a better teacher.
Related
I am using DosBox and I have a string read in from the buffer using an interrupt. I know where the first character is stored in memory, how do I increment to the next character?
0100 mov ah, 0a
0102 mov dx, 111
0105 int 21
0107 mov dl, [113] ;first character here
010b mov ah, 02
010d int 21
010f int 20
0111 db 0f
The question is how do I increment to the next character in the string? If I input the string "Hello" and then use inc dl it simply gives me the letter "I" instead of "e".
You need to pick a register to point at the current character. Once you have this there are instructions to advance your pointer as well as instructions to read the byte the pointer is pointing to.
Since you don't know how many characters will be read by the user input function, and you want this function to work with any input value, you'll need some sort of loop so you only print as many characters as have been read, although if you wanted to make it simple, you could make it only print the first 3 characters regardless of what was typed in. I'm going to assume you want to print out exactly what was typed by the user.
A good way to tackle this is to use the LOOP instruction which repeats (jumps into) the loop body by the count that has been placed into the CX register. Since the user input function gives us the character count, all we have to do is read that into the lower portion of the CX register (CL) for loop initialization. We'll also need a pointer to point to the current character. Once in the loop body, we'll just read whatever character is at our "current character" pointer and then call the DOS character-print function to output it to the console. Then we can advance the pointer and LOOP until all characters have been done. Note that each time the LOOP instruction is encountered, CX is decremented until it reaches zero. Once it is zero, LOOP no longer jumps back into the body and simply advances to the instruction following the LOOP.
NOTE: If you don't output a CRLF after reading the user input, there will be no line feed and the new output will overwrite where the input was read on the console. Effectively it will look like nothing happened.
Here's your modified sample:
0100 MOV AH,0A
0102 MOV DX,0123
0105 INT 21 ;input string using buffer at 0123
0107 MOV DX,0120
010A MOV AH,09
010C INT 21 ;output CRLF sequence first
010E MOV SI,0124 ;point SI at byte containing chars read
0111 XOR CX,CX ;CX = 0
0113 MOV CL,[SI] ;CX = chars_read
0115 INC SI ;mov SI to next char to display
0116 MOV DL,[SI] ;DL = character SI is pointing at
0118 MOV AH,02
011A INT 21 ;display character
011C LOOP 0115 ;loop back to INC instruction until no more chars left
011E INT 20 ;exit
0120 DB 0D ;CR
0121 DB 0A ;LF
0122 DB 24 ;"$" DOS string terminator
0123 DB 20 ;buffer start; max characters = 32
0124 DB 00 ; chars read goes here
0125 DB 00 ; input chars are read here
I want to put numbers from 0 - 9 to memory cells 400h to 409h.
So for example at 400h -> 0 (put 0) and at 401h -> 1 (put 1) ..... 409h (put 9).
This is my code so far: (I dont know if it works)
IDEAL
MODEL small
STACK 100h
DATASEG
;----------
;----------
CODESEG
start:
mov ax , #data
mov ds , ax
mov es, ax
;----------
mov si , 400h
mov cx , 10
mov al , 0
agian:
mov [si],al
inc si
inc al
loop agian
;--------
exit:
mov ax,4c00h
int 21h
END start
There's a very simple way to see if your program works. Just write the values in the video memory. That way you'll know if it works.
start:
mov ax, 0B800h ;NEW
mov ds, ax
mov es, ax
;----------
mov si, 400h
mov cx, 10
mov al, 48 ;NEW value 0 -> character 0
agian:
mov [si], al
add si, 2 ;NEW 1 character occupies 2 bytes in video memory
inc al
loop agian
mov ah,00h ;NEW wait for a keystroke so you can actually see
int 16h ;NEW ... the output
If you can invest the time you could learn to use the DOS utility DEBUG.EXE. Amongst other things it allows you to single step your program and view memory .
The easiest way to check if your ASM code is working the way you expect is to run it in a debugger. If you're running on Windows, OllyDbg 2 would be a good candidate — it will show you the current values of the registers, state of the stack, etc., so you can see how they change as you step through your code. You can modify the code from inside OllyDbg too.
You can write breakpoints in your code with the int 3 instruction, or use the debugger to place breakpoints at runtime.
I've tried reading about this all over the internet but here it is my problem. I am given a string of doublewords.
I have to order in decreasing order the string of the low words (least significant) from these doublewords. The high words remain unchanged.
For ex: strin DD 12345678h 1256ABCDh, 12AB4344h
the result would be 1234ABCDh, 12565678h, 12AB4344h.
Now I tried my best writting some code but it's not working properly, my insertion procedure. If you could take a look and tell me what I'm doing wrong, I'd be greatful.
I tried running it in td mode but I just can't figure out.
assume cs:code, ds:data
data segment
s dd 12345678h, 1256ABCDh, 12AB4344h
ls equ ($-s)/4 ;this is supposed to be the length of my source string
d dd ls dup (?) ;this is my destination string
aux dw ?
aux2 dw ?
data ends
code segment
insert proc
push di ;here I use the stack to get more free registers
push cx
cmp di, offset d ;if di=offset d it means that I didn't store any number yet
je addPrim
std ;we plan on working form right to left on the string for the next part
mov cx, di
sub cx, offset d ;here I find out with how many words I have to compare the word from AX
dec di
dec di ;since I work with doublewords, for some reason I thought I should decrease di
dec di ;3 times but here my procedure gets fuzzy and doesn't work properly anymore
repeta1: ;this repeat is supposed to compare the word from AX with the rest of the least
scasw ;significant words from es:di
jge DIplus2 ;if my number from AX is bigger or equal than what's in es:di, I increment
;di twice and store it
mov bx, word ptr es:[di+1] ;this part is supposed to interchange words but it's not
;working how I planned so I don't know how to change it
mov word ptr es:[di+2], bx
loop repeta1
jmp DIplus1
DIplus2:
inc di
DIplus1:
inc di
addPrim: ;this label just adds the first word in the destination string
stosw
pop cx
pop di
inc di
inc di
cld
ret
insert endp
start:
mov ax, data
mov ds, ax
mov es, ax
mov si, offset s
mov di, offset d
mov cx, ls ; store in cx the length of the strings
jcxz exit
repeta:
lodsw ;because of little endian, my first word will be my least significant word in the
;in the doubleword so right after it is moved in ax, i apply the procedure insert
call insert
lodsw ;here it moves in ax my most significan word in the dd, so i auto store it
stosw ;in my destination string
loop repeta
exit:
mov ax, 4c00h
int 21h
code ends
end start
ls equ ($-s)/4 ;this is supposed to be the length of my source string
This actually calculates the number of elements.
mov cx, di
sub cx, offset d ;here I find out with how many words ...
At the second invocation of your insert proc this will set CX=4 which is too big given a list of only 3 values. I suggest you divide CX by 4.
dec di
dec di ;since I work with doublewords...
dec di ;3 times but here my procedure gets fuzzy
This is certainly wrong. SCASW indicates you either decrement by 4 or not decrement at all!
mov bx, word ptr es:[di+1] ;this part is supposed to interchange words...
mov word ptr es:[di+2], bx
This cannot work since the offsets are only 1 byte apart!
jmp DIplus1
This yields an single increment of DI and thus an error because you want to store a word at that spot.
I'm one day into learning ASM and I've done a few tutorials, and even successfully modified the tutorial content to use jmp and cmp, etc instead of the MASM .if and .while macros.
I've decided to try and write something very, very simple to begin with before I continue with more advanced tutorials. I'm writing a Fibonacci number generator. Here is the source I have so far:
.386
.model flat, stdcall
option casemap :none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\masm32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\masm32.lib
.code
start:
mov eax, 1
mov ecx, 1
_a:
push eax
add eax, ecx
pop ecx
; Jump to _b if there is an overflow on eax
; Print Values Here
jmp _a
_b:
push 0
call ExitProcess
end start
I intend to check for overflows on eax/ecx but right now I'm just interested in displaying the values of eax/ecx on the screen.
I know how to push the address of a constant string from .data and call StdOut which was the first example in the hello world tutorial, but this appears to be quite different (?).
There is this code provided by Microsoft itself
http://support.microsoft.com/kb/85068
Note that this code outputs AX register on 16 bit systems. But you can get the idea, you just need to convert AX value into ASCII characters by looping through each character. Skip the interrupts part and use your StdOut function.
mov dx, 4 ; Loop will print out 4 hex characters.
nexthex:
push dx ; Save the loop counter.
mov cl, 4 ; Rotate register 4 bits.
rol ax, cl
push ax ; Save current value in AX.
and al, 0Fh ; Mask off all but 4 lowest bits.
cmp al, 10 ; Check to see if digit is 0-9.
jl decimal ; Digit is 0-9.
add al, 7 ; Add 7 for Digits A-F.
decimal:
add al, 30h ; Add 30h to get ASCII character.
mov dl, al
;Use StdOut to print value of dl
;mov ah, 02h ; Prepare for interrupt.
;int 21h ; Do MS-DOS call to print out value.
pop ax ; Restore value to AX.
pop dx ; Restore the loop counter.
dec dx ; Decrement loop counter.
jnz nexthex ; Loop back if there is another character
; to print.
See here as well:
http://www.masm32.com/board/index.php?PHPSESSID=fa4590ba57dbaad4bc44088172af0b49&action=printpage;topic=14410.0
I have an assignment from my comp. system org. subject and unfortunately I'm kind of new when it comes to assembly language. I'm supposed to write a program that displays the numbers 0,2,4,6,8,10 respectively. How would I go about this?
Maybe this'll answer my question: (Reactions please)
.model small
.stack 100H
.data
.code
call proc
mov cx,5
mov dx,0
L1:
mov bx,2
add dx,bx
mov ah,02h
loop L1
int 21
endp
Go see your lecturer and/or tutor and ask for advice. That's what they're there for. You haven't given us anywhere near enough info to help you out.
Here's what I think your ABCD program should look like. I suggest you use it as a baseline to try to make a 0 2 4 ... version.
model proc
.stack 100H
.data
.call
main proc
mov cx,10 ; 10 loops only.
mov dx,40h ; start dx at 'A' - 1.
L1:
inc dx ; move to next character.
mov ah,02h ; int 21,02 is print character.
int 21h
loop L1 ; loop until cx is 0
mov ax,4c00h ; int 21,4c is exit with al holding exit code.
int 21
endp
When you've at least had a go at converting this, post the code and we'll critique what you've done.
If you're taught something, it never lasts but, if you learn something, it lasts forever (alcohol-addled braincells notwithstanding :-).
Int 21 is the DOS interrupt which allows assembler programs to use various DOS functions. It's conceptually a huge switch statement based on the AH register which is why you'll see things like Int 21 Fn 02, which means execute mov ah,2 followed by int 21.
Int 21 Fn 02 will take the contents of DL and output that to the screen. So the sequence:
mov ah,02h
mov dl,41h
int 21h
will output the 'A' character (0x41).
Similarly, Int 21 Fn 4c will exit the current running process.
I'm sure your class gave you some education here.
Can you code enough assembly to print one or two numbers?
Can you code enough to calculate the numbers, even if you can't print them?
Post that much code, and you may find help here.
Otherwise, you're asking others to actually do your homework for you.
Assembly language is a symbolic representation of the numeric machine codes and other constants needed to program a particular CPU (or architecture). So assembly language for Macs (most recently Intel's X86) is different from that used to on the iPhone - ARM.
Your teacher is also probably expecting you to realise the difference between the binary form of the number you will count with, and the ASCII format you will use to display to the screen.
You do know there is more than one flavor of "Assembly Language."
You can do it exactly like the program which prints A, B, C, D, etc.: except that instead of starting at 'A', start at '0; and instead of increasing by 1 each time (from 'A' to 'B'), increase by 2 (from '0' to '2').
After printing '0', '2', '4', '6', and '8', the next number that you want to print is '10'.
To print '10', you can print '1' followed by '0'. Or, instead of invoking int 21 with ah=2 (which prints one character at a time), you can set ah=9 to print a string (set ds:dx to a block of memory which contains "10$").
Later you suggested the following solution and asked for criticism:
.model small
.stack 100H
.data
.code
main proc
call defineuser1
call defineuser2
mov cx,5
userdefine1 proc
L1:
mov dx,0
mov bx,2
add dx,bx
mov ah,02h
loop L1
int 21h
endp
userdefine2 proc
mov ah, 4ch
int 21h
userdefine2
endp
My criticisms are as follows:
defineuser1 doesn't exist (I think you mean userdefine1)
setting cx needs to be inside (not before) the procedure
invoking int 21 needs to be inside (not outside) the loop
you need special handling for "10" as I mentioned above
There's a difference between '0' (the ASCII character/digit) and 0 (the number) ... you need to print the character/digit, not the number
You need to learn to test your code (write it, step through it with debugger, and debug it), preferably before you post questions about it.
You would have a counter beginning at zero and repeatedly increment it by two, printing the result.
.model small
.stack 100H
.code
.data
var2 DB "10$"
main proc
mov cx,4
mov ax,0
mov dl,al
add dl,30h
mov ah,02h
int 21h
mov ax,0
var1:
add ax,2
mov dl,al
add dl,30h
mov bx,ax
mov ah,2h
int 21h
mov ax,bx
loop var1
mov ax,#data
mov ds,ax
mov dx,offset var2
mov ah,09h
int 21h
main endp
end main
I'm new in computer science and when i saw this question i just wanted to try it. I have managed in doing it and here is the code
MOV AX, 0
MOV BX, 2
ADDLOOP:
ADD AX, BX
CMP AX, 10
JE DONE
JMP ADDLOOP
DONE:
Ok. That's my best attempt. Lots of details left out. I should also mention that I have no frigging clue how to print a char to the screen.
Like others have mentioned, you didn't specify which assembly language so I chose x86.
Finally, go talk to your instructors, they'll help you much more than we can.
Are you using a macro for the output?
should be something like...
mov eax, 0
myloop: cmp eax, 10
jg done
output macro eax
add eax, 2
jmp myloop
done:
of course that's for 8086 assembly.