0

Assembler throws error for my 16 bit code movzbw (%ax), %ax Error: `(%ax)' is not a valid base/index expression

But the below instruction is valid on 32 bit code generation. movzbl (%eax), %eax

Environment: Processor: Intel(x86) Assembler: "GNU AS" Operating System: "Linux" Purpose: While writing a very simple bootloader which prints "Hello, World" to the screen, I am trying to pass a string to a function and then traverse byte by byte and then print it.

What is the equivalent instruction that I can use to avoid error in writing 16 bit real mode code?

More information: Below is the C code that I am trying to simulate in "16 bit GNU AS" assembler

void _prints(char*);


int main(void)
{
   char* mess = "hello";
   _prints(mess);
   return 0;
}

void _prints(char* str)
{
   while(*str)
   {
      ++str;
   }
}

Note:While trying to generate the assembly file using command "gcc -S test.c", I see that in _prints function the instruction "movzbl (%eax), %eax". I want to simulate a 16-bit real mode code using the same assembler, but it throws error while using "movzbw (%ax), %ax"

Please help

1 Answers1

2

In real mode, (%ax) ([ax]) is not a valid indirect addressing method. You have to use the %bp register. I recommend you pick up the Intel (or AMD) processor manuals and read Volume 2 (for Intel) from front to back, as I did.

If you are just removing the e to simulate real mode, there is no need. Your program will not compile to a 16-bit executable. It will still be a 32 or 64 bit executable with gcc. The only way to generate 16-but executables is with OpenWatcom. Even then, there is no need to write 16-bit programs. They are slow and the switching between real and protected mode (change executing thread) is expensive on the processor.

As you mentioned this is for a bootloader, you can't write a bootloader like this. You have to write the assembly by hand. No exceptions that I'm aware of.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
Cole Tobin
  • 9,206
  • 15
  • 49
  • 74
  • In 16-bit mode, real or protected. – Alexey Frunze Apr 14 '13 at 08:35
  • .code16 .section .data message: .ascii "Welcome to c0mrade" .section .text .globl _main _main: pushw message call _putchar jmp _hang _putchar: pushw %bp movw %sp, %bp _putcharl: movw 4(%bp), %ax movzbw (%ax), %ax testb %al, %al je _putchare movb $0x0e, %ah movb $0x00, %bh movb $0x07, %bl int $0x10 addw $1, 4(%bp) jmp _putcharl _putchare: movw %bp, %sp popw %bp ret _hang: jmp _hang .section .boot_signature .word 0xaa55 .end –  Apr 14 '13 at 08:38
  • sorry for the code indentation.....but the code does not work as expected "Traversing byte by byte and print the character" –  Apr 14 '13 at 08:42
  • You can't write a bootloader this way. A compile outputs object files that are more than just code. Those are then linked into an _executable_ with sections. A bootloader is _raw_ assembly and has _no_ sections. – Cole Tobin Apr 14 '13 at 08:43
  • but i was able to generate a binary out of this program and was able to run through bochs x86 emulator. –  Apr 14 '13 at 08:46
  • You may e able to make a binary, but it still is an executable, _not_ raw code. If you want to write a bootloader, (pardon my French) RTFM. – Cole Tobin Apr 14 '13 at 08:48
  • Probably you will have to look into my source files, linker files and makefile for generation of binary. But I am sure that I am generating a flat binary file. –  Apr 14 '13 at 08:57
  • Ok, but GCC doesn't output 16-bit code. So you may be generating a flat binary, but it is 32-bit code. Incidentally, the 32-bit code may interpret to functionally equivilent 16-bit code, but it isn't 16-bit code. – Cole Tobin Apr 14 '13 at 09:21
  • Oh sorry...I am not using gcc but instead i am using "GNU AS" assembler –  Apr 14 '13 at 09:27
  • Then what seems to be the problem? If you want to code your bootloader in C, you can't. – Cole Tobin Apr 14 '13 at 09:29
  • I knew it already but I am trying to understand how to write a function which traverses through the string and print it byte by byte to the screen in 16-bit real mode using stacks in GNU AS assembler in AT&T syntax. –  Apr 14 '13 at 09:35
  • You need to learn interrupts. – Cole Tobin Apr 14 '13 at 10:07
  • @ColeJohnson There is a 16 bit protected mode since the 286. – demonkoryu Apr 30 '13 at 23:11
  • @demonkoryu Are you referencing the dreaded "Unreal mode"? – Cole Tobin Apr 30 '13 at 23:57
  • @ColeJohnson No, that's 16 bit real mode with 32 bit flat descriptors in shadow segment registers. For PM16, I'll refer you to here: www.osdever.net/tutorials/view/protected-mode – demonkoryu May 02 '13 at 21:51
  • @demonkoryu Oh that. That's not protected mode _per se_, but it is. It's actually called [Virtual 8086 Mode](http://wiki.osdev.org/Virtual_8086_Mode) – Cole Tobin May 02 '13 at 22:13
  • @ColeJohnson No, V86 mode is a virtualization of (16 bit) Real Mode from within PM that's only available since 386 (as is PM32). PM16 exists since 286. – demonkoryu May 03 '13 at 09:13
  • @demonkoryu Oh! The 286. I don't really consider the 80286 a protected mode processor as it is still 16-bit. – Cole Tobin May 03 '13 at 14:14
  • @ColeJohnson The defining feature of Protected Mode is a memory protection mechanism, which Real Mode lacks. The size (16/32bit) or layout (segmented/flat) of the memory space doesn't change the principle. – demonkoryu May 03 '13 at 21:09
  • @demonkoryu No, I agree with you that it is. I'm just saying that if you ask an assembly programmer about Protected Mode, they'll think of the 32-bit mode before the 16-bit mode. I have yet to see an operating system that runs in 16-bit protected mode. – Cole Tobin May 03 '13 at 21:38
  • OS/2 1.x and Windows 3.x used PM16, but I agree, it's not like anyone on the world would be targeting PM16 today. – demonkoryu May 03 '13 at 22:00