This is a bit off-topic in comp.lang.c, so I'm mailing my reply directly
to you instead.
Hello!
I got the following Code in Assembler (NASM), which prints out "5" in
realmode:
mov ax, 0xB800
mov es, ax
mov byte [es:0], '5'
I want to do the same in gcc now, but I'm stuck. GCC doesn't like the [es:0]
syntax...
asm("mov %ax, 0xB800");
asm("mov %es, %ax");
asm("mov [%es:0], '5'"); <-- Error about "[" :-(
Can anyone help me how to do this?
That's just so wrong on so many levels... sorry, but it really is.
First of all, the reason GCC is complaining to begin with is because
that construct is written "0(,1)" in gas syntax, if I recall correctly.
There are many other errors in your assembly syntax, since gas doesn't
use the same syntax as native x86 assemblers like NASM. In fact, there's
not a single part of that assembly code that is correct. You should read
about the differences in the gas texinfo, under the "Machine
Dependencies" section, "i386-Dependant" subsection.
Second, that code assumes that your program is running in real mode,
which it won't - GCC only compiles 32-bit code. After that, how to do
what you want depends on the operating system the program will be
running on. Many systems won't even allow you to do that, for
multitasking protection purposes. If you run that program on Linux, a
NTOS kernel (that is, WinNT4, Win2k or WinXP) or some other x86 UN*X,
for example, it will crash and burn.
If you're compiling it for DOS with DJGPP to run under some DPMI
interface like DOS4GW or a Win9x kernel, it's possible to get it to do
what you want, but it was quite some time since I programmed under DPMI
interfaces, so I don't really recall all the details. IIRC, you still
have to unprotect that memory and add it to your segment. When you have
done so, that memory will be available on the linear address that
corresponds to the real-mode address that you wish to access. B800:0000
in real mode corresponds to the linear address 000B8000. This is because
real mode addresses a 20-bit address bus by shifting the segment
register four bits to the left and adding the offset to that to produce
an address bus value.
If you manage to look up somewhere how to unprotect the memory (it's
somewhere in the DJGPP manual), the following assembly code would
accomplish your purpose:
asm("movl $0x35, 0xb8000(,1)");
You mustn't touch the segment registers in protected mode unless you
really know what you're doing, since in protected mode, the segment
registers cease to be segment registers, and are instead selector
registers, for selecting the segment descriptor you wish to operate
through (a segment in protected mode is _not_ the same thing as in real
mode). For more info on this, I suggest reading "Intel Architecture
Software Developer's Manual, Volume 3: System Programming", published by
Intel, order number 243192, downloadable as PDF through Intel's website.
Or can I also do this directly in C with pointers and don't use the asm() at
all? I couldn't get this to work either...
Indeed:
struct {
char glyph, color;
} *textmem = (void *)0x000b8000;
textmem[0].glyph = '5';
That will accomplish the same as the assembly code I gave above. Of
course, since it will most likely yield the exact same assembler output,
it is subject to the same operating system and protection constraints as
described above.
Fredrik Tolf