Confusion in memory segmentation in x86

Here I created the code for writing ASCII characters to 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 the kernel.c file shown below:

 void main() { extern void put_in_mem(); char c = 'e'; put_in_mem(c, 0xA0); } 

The above code is for printing "e" at the beginning of the second line in QEmu, but it is not. I tried debugging this with 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 is the value not loaded into the bx register?

In addition, I thought that move instructions use the ds register as the base of their segments and remove all addresses from the contents of ds. Therefore, according to these considerations, I suggested that when

 mov [si], cx 

The contents of the cx register will be located at 0xb8a0. It's right? Can the mov instruction affect any other segregation registers (e.g. cs, es, etc.)?

+6
source share
2 answers

There are a couple of problems with the _put_in_mem program, it does not save the DS and SI registers, which must be stored in accordance with the 16-bit x86 calling conventions, see section 6 of this document , and it does not save the bytes of characters and attributes 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 is one way to fix this:

 .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. The 0x7 attribute means displaying in light gray on a black background ... see http://wiki.osdev.org/Printing_To_Screen and <a2>

+4
source

Make sure this is not a memory reference by accident. Since your gdb output is similar to & t, it usually shows $ for immediate ones. Thus, it is suspicious that you really have a bx load with the contents of memory at 0xb800. Can you check the machine code?

Machine Code: 0xb8001e8b

Indeed, this machine code is for loading from memory. Looking at the as86 manual , you can see:

 # Prefix for immediate operands. mov ax,#1234 Immediate value, ax becomes 1234. 

Therefore, you must prefix your subscribers with the # sign. Please note that this applies to all transactions.

While this fixes the issue you asked for, see @amdn's answer for other issues you have.

+3
source

Source: https://habr.com/ru/post/982951/


All Articles