2

i have the following piece of code, which does not work (anymore). I remember that it already worked a few months ago. Maybe this is an compiler issue?

Im working on a little operating system. Just for understanding how it works in detail. And i wanted to start using C, as it is more readable than assembler.

My C code in question is:

#ifndef _CODE16GCC_H_
#define _CODE16GCC_H_
asm(".code16gcc\n");
#endif

#define VIDEO_MEM 0xB8000
#define WIDTH 80
#define HEIGHT 25

asm("call main\n");
asm("xor %eax, %eax\n");
asm("xor %ebx, %ebx\n");
asm("int $0x21\n");

void main(void)
{
    unsigned char* mem = (unsigned char*)VIDEO_MEM;

    for(int x = 0; x < 80; x++)
    {
        for(int y = 0; y < 25; y++)
        {
            *mem = 'A';
            mem++;
            *mem = 0x07;
            mem++;
        }
    }

    asm("xor %ax, %ax;int $0x16;");
}

I compile it with:

gcc -m32 -Os -march=i686 -ffreestanding -fno-stack-protector -Wall -Werror print.c -o print.o

and link using:

ld -m elf_i386 -static -Tlinker.ld -nostdlib --nmagic print.o -o print.elf

and create a binary by using:

objcopy -O binary print.elf -o print.bin

(Thats basically from a makefile we used in the university to write a little bootloader)

My problem now is, that the produced assembly code seems to be wrong: objdump -d -M intel print.o yields:

print.o:     file format elf32-i386


Disassembly of section .text:

00000000 <.text>:
   0:   66 e8 fc ff             callw  0 <.text>
   4:   ff                      (bad)  
   5:   ff 66 31                jmp    DWORD PTR [esi+0x31]
   8:   c0 66 31 db             shl    BYTE PTR [esi+0x31],0xdb
   c:   cd 21                   int    0x21

Disassembly of section .text.startup:

00000000 <main>:
   0:   66 ba 00 80             mov    dx,0x8000
   4:   0b 00                   or     eax,DWORD PTR [eax]
   6:   66 31 c0                xor    ax,ax
   9:   67 c6 04 42             mov    BYTE PTR [si],0x42
   d:   41                      inc    ecx
   e:   67 c6 44 42 01          mov    BYTE PTR [si+0x42],0x1
  13:   07                      pop    es
  14:   66 40                   inc    ax
  16:   66 83 f8 19             cmp    ax,0x19
  1a:   75 ed                   jne    9 <main+0x9>
  1c:   66 83 c2 32             add    dx,0x32
  20:   66 81 fa a0 8f          cmp    dx,0x8fa0
  25:   0b 00                   or     eax,DWORD PTR [eax]
  27:   75 dd                   jne    6 <main+0x6>
  29:   31 c0                   xor    eax,eax
  2b:   cd 16                   int    0x16
  2d:   66 c3                   retw   

The main function itself looks good to me. But what is going on in the very first section? The part i wrote using inline assembly. Its just random instructions and even a (bad) bit.

I know for sure, that this used to work. But what am i missing now? Is this an issue of GCC 8.2.1? Or is my code just incorrect?

I appreciate any help!

Levin Palm
  • 21
  • 1
  • 3
    Using generated _C_ code in 16-bit real mode is very tricky to get rightand unless you know what you are doing I don't recommend it. One problem is that unless you are in unreal mode `0xB8000` will not be accessible although it might work on QEMU because they don't do range checks on memory operands to see if they exceed the segment limits. Your `objdump` output looks off because by default it is decoding as 32-bit. Try adding the option `-Mi8086,intel` – Michael Petch Feb 16 '19 at 11:49
  • 3
    [don't use multiple separate `asm()` statements](https://stackoverflow.com/q/27685548/995714#comment85353418_27687809). That may get you into trouble – phuclv Feb 16 '19 at 12:47
  • Don't lie to your compiler: GNU C Basic Asm doesn't have any clobbers, but you're modifying registers! – Peter Cordes Feb 16 '19 at 16:06
  • 1
    Don't disassemble the `.o` as a 32-bit object, it holds 16-bit code. (And BTW, you can use `gcc -m16` to make it add `.code16gcc`). Disassemble the flat binary. – Peter Cordes Feb 16 '19 at 18:15
  • I just downloaded the virtual machine we got supplied with in the university. It uses GCC 7.2.0, and the EXACT same code works there! So they must have changed something in GCC8, don't they? – Levin Palm Feb 16 '19 at 21:01
  • But thanks for pointing out the things you did. The 16-Bit/32-Bit flags helped a lot! The dump now displays the correct instructions! – Levin Palm Feb 16 '19 at 21:02

0 Answers0