6

I have the following code, where I am trying to implement a function that prints string using the BIOS functions:

int printString(char* string)
{
 int i = 0;
 while (*(string + i) != '\0')
   {
    char al = *(string + i);
    char ah = 0xe;
    int ax = ah * 256 + al;
    interrupt(0x10,ax,0,0,0);
    i++;
   }
 return i;
}

The function interrupt is implemented in assembly. It calls the appropriate BIOS interrupt, as given by the first argument, with rest of the arguments containing the contents for ax,bx,cx and dx register respectively:

.global _interrupt
_interrupt:
push bp
mov bp, sp
push si
push ds
mov ax, #0x100
mov ds, ax
mov ax, [bp + 0x4]
mov si, #intr
mov [si + 1], al
pop ds
mov ax, [bp + 0x6]
mov bx, [bp + 0x8]
mov cx, [bp + 0xa]
mov dx, [bp + 0xc]
intr: int #0x0
pop si
pop bp
ret

Since I am using BIOS interrupts I am using 16-bit mode to compile this code. I used the following command:

bcc -ansi -c -o printString.o printString.c

I want to test this code in GDB, but when I try to load this printString.o file into gdb using:

gdb printString.o

I get the following error:

"/home/kern/printString.o": not in executable format: File format not recognized

I also tried changing the GDB to 16-bit format using:

set architecture i8086

But still this error is coming. How can I load a 16-bit code into GDB?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
sarthak
  • 774
  • 1
  • 11
  • 27
  • You can't run object files in `gdb`, no matter how many bits. You need to make an executable, as the error message says. For 16 bit code, you will also need a 16 bit environment, such as `qemu`. – Jester Mar 02 '15 at 14:15
  • @Jester But it is used in 32 bit mode with gcc. The command `gcc -g program.c -o programname` is used to generate an object code and is run using `gdb programname ` – sarthak Mar 02 '15 at 15:07
  • Yes, now play `spot the difference` with the two command lines. Notice that the `gcc` one does **not** have `-c` and produces executable (also hinted by the missing `.o` extension) but your `bcc` **does** have the `-c` (which means compile to object) and also the output has the `.o` extension. – Jester Mar 02 '15 at 15:08
  • @Jester ok..I also tried linking using ld86 command. But it still shows the same error. Doesn't ld86 produces executable code? Is there no other way to convert the .o file into executable and use it in GDB? – sarthak Mar 02 '15 at 15:21
  • 1
    ld86 does produce executable, but that is a 16 bit executable that you can't load into your native operating system (which you didn't specify, but I assume linux). For the OS, that does not qualify as an executable. That's why you need something that can run your 16 bit code and provide the expected BIOS services. This is what `qemu`, `bochs` or `dosbox` can do. – Jester Mar 02 '15 at 15:24

2 Answers2

15

Minimal QEMU example

qemu-system-i386 -hda main.img -S -s &
gdb -ex 'target remote localhost:1234' \
    -ex 'set architecture i8086' \
    -ex 'break *0x7c00' \
    -ex 'continue'

where main.img is a boot sector.

  • break *0x7c00: the first instruction will not be your boot sector, but rather 0x0000fff0 which does the BIOS setup, see also. So we use this to start from where the boot sector gets loaded to.
  • set architecture i8086: for regular ELF executables, GDB can decide architecture from the headers. But for raw boot sectors, there is no such metadata, so we have to tell it.

See also:

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
7

As Jester says in the comments, you cannot run object file with gdb.

And you can not run a 16-bit executable file or 16-bit assembly code with gdb. You must use something like qemu to run your code on an emulated CPU and connect to it using gdb, or you can use dosbox in order to run your code and use a debug program on DOS. And remember, using BIOS interrupts is an error on a modern OS, like Linux, because at start up these operating systems disable BIOS interrupts.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
Parham Alvani
  • 2,305
  • 2
  • 14
  • 25
  • 1
    [BOCHS](http://bochs.sourceforge.net/) has a good built-in debugger ([docs](http://bochs.sourceforge.net/doc/docbook/user/internal-debugger.html)). It's highly recommended for bootloader development; it understands segmentation (unlike GDB), and can parse and print the IDT / GDT / page tables for you so you can double-check that you stored the right data in them. It can also show you exception details. – Peter Cordes May 23 '20 at 19:15