Page 1 of 1
Assembler string output in RM does not work
Posted: Mon Sep 28, 2009 11:56 am
by jkrug
Hi,
because I don't have a very good command of assembler although I need it often for my OS I've decided to become acquintated with it. I've just written a mini-RM program that should simply print a string to the screen using BIOS interrupts. Assembling and starting in QEMU works well but the program behaves strange when I try to put a string to the screen (he puts out small delta signs in an endless loop. Following code:
Code: Select all
[BITS 16] ; generate 16bit real mode code
[ORG 0x700] ; start address of code is 0x700
; jump to start label (without segment prefix -> 0x0:)
jmp 0x00:start
start:
cli ; clear interrupt flag
; setup working stack
mov ax,0x9000
mov ss,ax ; set stack base address to 0x9000
mov sp,0 ; set stack pointer to 0
sti ; set interrupt flag
mov dx,msg
push dx
call printstr
jmp short $
msg db 'Welcome to simpleOS!',10,0 ; welcome message
; print string
printstr:
pop dx
mov si,dx
_loop:
mov al,[si]
mov ah,0x0E ; move attribute byte to 0x0E
int 0x10
mov al,[si] ; just in case the BIOS interrupt modifies the register
inc si
cmp al,0 ; compare al and 0
jne _done ; if they are equivalent, jump to the 'done' label
jmp _loop
_done:
ret
times 512-($-$$)-2 db 0 ; $ stands for the current line offset
; $$ stands for the offset into the section
dw 0xAA55
Can anybody tell me what's wrong with it? I guess it's something very simple I just don't get.
Thanks
jkrug
Re: Assembler string output in RM does not work
Posted: Mon Sep 28, 2009 12:57 pm
by Hangin10
When you're getting the function arguments, the first item on the stack is going to be the return address. Assuming a near call, you'll want the second word (SP+2). Or use the frame pointer, in which case the third word:
and then at the end:
Re: Assembler string output in RM does not work
Posted: Mon Sep 28, 2009 1:04 pm
by beyondsociety
I see a few problems with your code that may make it not work for you, suggestions, etc.
[ORG 0x700] ; start address of code is 0x700
Why are you starting out your code at location 0x700? Never seen that as a loading address, you will want 0x7c00 as the address if this is part of a bootsector and i assume it is considering you have
times 512-($-$$)-2 db 0 ; $ stands for the current line offset
; $$ stands for the offset into the section
dw 0xAA55
at the bottom of the assembly file, otherwise you would want to try loading at 0x100 and assembling it to a .com file
You really don't need the cli/sti in between setting up the stack, more or less a personal perference. As for your location for your realmode stack, cant remember if that is a good place to put it or not, been a while since I've written code for real mode. the other code looks all right to me, though havent tested it in a emulator.
Hope this helps.
Re: Assembler string output in RM does not work
Posted: Mon Sep 28, 2009 1:22 pm
by Combuster
It is generally easier to use a register-calling-convention in asm-only code.
And your stack is in reserved memory
Re: Assembler string output in RM does not work
Posted: Mon Sep 28, 2009 2:11 pm
by jkrug
Okay, thank you for your help. I've come to the conclusion that I don't understand a basic concept for when I try to put out a single character like this:
Code: Select all
[BITS 16] ; generate 16bit real mode code
[ORG 0x7C0] ; start address of code is 0x700
; jump to start label (without segment prefix -> 0x0:)
jmp 0x00:start
start:
; setup working stack
mov ax,0x9000
mov ss,ax ; set stack base address to 0x9000
mov sp,0 ; set stack pointer to 0
sign db 'H'
; print character to screen
mov al,[sign]
mov ah,0x0E
int 0x10
jmp $
times 512-($-$$)-2 db 0
dw 0xAA55
he puts a 'F' to the screen. (I should definitely spend a little bit more time in getting the assembler basics and not only work on C/C++ level
) What's wrong with this?
Cheers
jkrug
PS: If 0x9000 is protected memory, is there a better place for the stack?
//edit: I just looked up in a memory map and 0x9000 has been describben as freely usable memory there.
Re: Assembler string output in RM does not work
Posted: Mon Sep 28, 2009 2:22 pm
by Combuster
Looks like you copied everything and understood nothing.
Start with reading
Real Mode addressing, then ask again.
Re: Assembler string output in RM does not work
Posted: Mon Sep 28, 2009 3:56 pm
by geppyfx
interesting piece of code you got here
sign db 'H' gets treated as code. But by lucky coincidence it corresponds to
dec ax instruction
mov al,[sign] uses DS register which you did not setup, but since you did set CS register you can overwrite DS: mov al, [CS:sign]
Code: Select all
[BITS 16] ; generate 16bit real mode code
[ORG 0x7C00] ; 0x7C00
; jump to start label (without segment prefix -> 0x0:)
jmp 0x00:start
start:
; setup working stack
mov ax,0x9000
mov ss,ax ; set stack base address to 0x9000
mov sp,0 ; set stack pointer to 0
xor ax, ax
mov ds, ax
jmp next_code
sign db 'H'
next_code:
; print character to screen
mov al,[sign]
mov ah,0x0E
int 0x10
jmp $
times 512-($-$$)-2 db 0
dw 0xAA55
and I can't tell anything about int10 function becaouse i don't remember that stuff
Re: Assembler string output in RM does not work
Posted: Tue Sep 29, 2009 9:15 am
by jkrug
@Combuster: The code is not copied although I do not really understand it. I know how it works in theory but I just can't put it into practice.
@geppyfx: It works now when I've applied your tips. I just got a bit confused about all this leaving-different-parts-out-to-see-if-it-works-then stuff so I forgot to set the ds register again
. Thank you for your help!
Cheers
jkrug
PS: int 0x10 is working, I tried before by moving the constant ascii code for 'a' into al and it worked.
PPS: I got now what I originally wanted: putting out a string to the screen with this code:
Code: Select all
[BITS 16] ; produce 16bit real mode code
[ORG 0x7C00] ; organize code on 0x7C0 where it gets loaded by the BIOS
jmp 0x00:start ; jump to 'start' label (with sr prefix 0x00: -> cs = 0)
start:
; setup a working stack at address 0x9000 (should be free for own use)
mov ax,0x9000
mov ss,ax ; set stack base address to 0x9000
mov sp,0 ; set stack pointer to 0
; setup working environment
xor ax,ax ; get zero into AX
mov ds,ax ; set DS to zero
mov es,ax ; set ES to zero
; jump to actual start function
jmp _start
; reserve some memory for the welcome string to output
msg db 'Hello',0
_start:
mov ax,msg ; move sign address to ax
push ax ; push address to stack
call screen_write
jmp $ ; jump into endless loop
; this function writes a string to the screen
screen_write:
pop ax ; pop return address from stack
pop ax ; pop string base address from stack
mov si,ax ; move base address to SI
_char_loop:
lodsb ; load character currently being located at the address
; stored in SI to AL
cmp al,0 ; compare AL and 0: 0 is subtracted from AL and if zero
; comes out, the zero flag is set
je _end ; if they are equivalent (-> zero flag is set), jump to end
mov ah,0x0E ; move attribute byte to AH
int 0x10 ; raise BIOS interrupt
jmp _char_loop
_end:
ret
times 512-($-$$)-2 db 0 ; $ stands for the current line offset
; $$ stands for the offset into the section
dw 0xAA55
Re: Assembler string output in RM does not work
Posted: Tue Sep 29, 2009 9:42 am
by Andr3w
Code: Select all
_start:
mov ax,msg ; move sign address to ax
push ax ; push address to stack
call screen_write
jmp $ ; jump into endless loop
I think you don't really need an infinite loop at this time. If you wanna stop execution, I'd recommend you to halt the processor using
Code: Select all
cli ; disable interrupts
hlt ; halt - will continue execution after an exception or IRQ
; (we disabled interrupts, so this will stop the processor)
Or, if you don't wanna halt the system, I'd recommend you to use this to stop fan from working everytime:
Code: Select all
INFINITE_LOOP:
hlt ; halt - will continue execution after an exception or IRQ
jmp INFINITE_LOOP ; jump to INFINITE_LOOP and wait for another exception or IRQ
Correct me if I'm wrong!
-- Andrew
Re: Assembler string output in RM does not work
Posted: Tue Sep 29, 2009 10:23 am
by Hangin10
Instead of pointing something out, I'm just going to suggest you try printing two strings (call your print string function twice).
Re: Assembler string output in RM does not work
Posted: Tue Sep 29, 2009 12:06 pm
by jkrug
Hangin10 wrote:Instead of pointing something out, I'm just going to suggest you try printing two strings (call your print string function twice).
Oh yes, I forgot that I have to push the return address again. Is running now, thanks for the hint. It is astonishing how much more I learn about assembler when I try to write a simple program like this than I've learned by reading a whole tutorial.
@qandrew: Makes sense, I've replaced the jmp $ now with
Cheers
jkrug