Confusion in Memory segmentation in x86
assembly, c, x86
Solution
There are a couple of problems with the routine _put_in_mem, it doesn't preserve registers DS and SI which must be preserved according to 16-bit x86 calling conventions, see section 6 of this document, and it doesn't store the character and attribute bytes properly.
.global _put_in_mem
_put_in_mem:
push bp
mov bp, sp
mov cx, [bp + 4]
mov si, [bp + 6] # si must be preserved across function calls
mov bx, 0xb800
mov ds, bx # ds must be preserved across function calls
mov [si], cx
add bx, 0x1
mov cx, 0x7 # low byte 0x7, upper byte = character = 0x00
mov [si], cx # si has not changed... overwriting with 0x0007
pop bp
ret
Here's one way to fix it:
.global _put_in_mem
_put_in_mem:
push bp
mov bp, sp
mov cx, [bp + 4] # cx = xxcc, where cc is ASCII character
mov ch, 0x7 # attribute byte: light-grey on black
mov bx, [bp + 6] # bx = offset into VGA video buffer
mov ax, 0xb800 # VGA video buffer base at 0xb800 x 16
mov es, ax # use ES segment register instead of DS
mov es:[bx], cx # store ASCII at es:[bx], attribute at es:[bx+1]
pop bp
ret
The VGA `attribute` byte follows the character byte in text mode. An attribute of 0x7 means to display as light-grey on black background... see http://wiki.osdev.org/Printing_To_Screen and http://en.wikipedia.org/wiki/VGA-compatible_text_mode
Problem
Here I made a code for writing ASCII characters into VGA Memory: ``` .global _put_in_mem _put_in_mem: push bp mov bp, sp mov cx, [bp + 4] mov si, [bp + 6] mov bx, 0xb800 mov ds, bx mov [si], cx add bx, 0x1 mov cx, 0x7 mov [si], cx pop bp ret ``` This is called through a kernel.c file shown below: ``` void main() { extern void put_in_mem(); char c = 'e'; put_in_mem(c, 0xA0); } ``` The above code was meant to print "e" on the beginning of the second line in QEmu, but it did not. I tried to debug this using GDB and found that the command ``` mov bx, 0xb800 ``` in GDB has become ``` mov -0x4800,%bx ``` and the value in ebx after this command is 0x0. Why has the value not loaded in the bx register? Further, I thought that the move instructions use ds register as their segment base and offset all the addresses from the contents of ds. So according to this reasoning, I assumed that when ``` mov [si], cx ``` instruction the contents of cx register will be placed at the address 0xb8a0. Is this correct? Can mov instruction be affected by any other segement registers (like cs, es etc.) as well?