• Please review our updated Terms and Rules here

Debugging 8088 programs

otacon14112

Experienced Member
Joined
Apr 19, 2012
Messages
115
Location
Iowa, United States
How do you guys debug 8088 programs?

I can't get gdb to work with 8088 programs. Gdb works with elf executables, but I'm having great difficulty trying to to debug my 8088 binary programs. They were designed to fit onto a 2k ROM chip, and they won't run in DOSBox, or any other emulator because my homebrew computer might not be exactly like the IBM PC. I've spent several days now just trying to find some way to debug my programs.

What I've been doing so far is saving binary to the EEPROM and powering it up, but it would be so much better if I could debug it and watch the registers and stuff as it goes.

Emulators don't work because many emulate DOS, and always have a built-in BIOS. Many debuggers don't recognize my 8088 binaries. I've spent so much time that I have decided to ask for help on this. Can a program meant to reside in FFFF0h be ran in a debugger?

Thanks to anyone who can help me.
 
Last edited:
The fancy way to debug any 8088 code is to use IDA and hook it to a qemu-based virtual machine. Since that is a lot of work (and potential expense, if you can't do this with the free version of IDA), it is easier to just grab a debugger and run it in an emulator. DEBUGX will let you load your block of code anywhere in memory and then start executing it, but for better control, use a visual debugger such as Insight. You can also use the debugger built into emulators, such as Bochs or DOSBox (have to start with an option to get the debugger to work).

What about a built-in BIOS makes it difficult to debug 2K of 8088 code? Are you calling interrupts that the BIOS is picking up, perhaps? As for a debugger not recognizing your binary, I'm having trouble understanding that. Even the old DEBUG.COM will let you load a binary file anywhere you want in memory. Some more details might help understand where you're getting tripped up.
 
Thank you for your reply!

DEBUGX will let you load your block of code anywhere in memory and then start executing it, but for better control, use a visual debugger such as Insight. You can also use the debugger built into emulators, such as Bochs or DOSBox (have to start with an option to get the debugger to work).
Debug wouldn't work, so I downloaded debugx, but that didn't work, either. On top of that, Insight wouldn't install. I'm currently looking into this, but I researched insight, and found that it was made by Red Hat as a front end to gdb. The thing is, I had already tried one GUI for gdb, ddd, and it, too, would not recognize the raw ROM file.

What about a built-in BIOS makes it difficult to debug 2K of 8088 code? Are you calling interrupts that the BIOS is picking up, perhaps? As for a debugger not recognizing your binary, I'm having trouble understanding that. Even the old DEBUG.COM will let you load a binary file anywhere you want in memory. Some more details might help understand where you're getting tripped up.

My raw binary assembly is not recognized by any debugger I've tried so far as an executable program. The 8088 runs the binary when it's saved in the EEPROM, but I haven't been able to get anything to open it in order to debug it. I haven't been able to find what option (if any) for any debugger to debug an 8088 ROM program.

I'm really trying to learn how to do this. Would compiling my ROM image as an object matter? Do I really need to compile it with elf format? Even if this caused a debugger to successfully recognize it as a file containing CPU instructions, I would think that by doing so it would alter the contents of the file from what the 8088 would be seeing.
 
Last edited:
My go-to 8088 debugger lately has been the one built in to DOSBox (http://www.vogons.org/viewtopic.php?f=32&t=7323). The oldskool, hardware way to debug a boot ROM would have been to use an expensive (and probably hard-to-find, now) in-circuit-emulator that replaces the CPU. Nowadays it's probably much easier to use a software-based emulator. As you correctly surmised, the first problem is going to be persuading whatever emulator you use to load the ROM image and run it in the appropriate way.

First question: if your ROM is loaded into a different segment (but at the correct offset within that segment) do you expect it to work properly? If so, then your job is much easier - you can just write a little .com file stub that loads the ROM image and jumps to the appropriate address, then start the debugger with that.

If the ROM will only work at FF80:0000 then your best bet may be to modify an emulator to load your ROM instead of its own BIOS and recompile it. DOSBox isn't super difficult to modify and recompile (especially on Linux).

As for the problem of emulating your custom hardware instead of a vanilla IBM PC, again this seems like a problem that's quite solvable by modifying DOSBox. If it's just a matter of removing hardware or moving some things around in the memory (or port IO address, or IRQ, or DMA) map, those should be pretty easy changes to make. If your hardware has some peripherals that the emulator doesn't currently emulate then you'll just have to write your own emulations of those peripherals and integrate them, which is a bit more work but may very well end up saving you time in the long run.

I'd advise against trying to compile your ROM into an ELF binary - that's a rabbit hole and doesn't actually solve the real problem of persuading an emulator to load your ROM file at the correct address and run it in the correct way.
 
Can a program meant to reside in FFFF0h be ran in a debugger?

Yes, if the program is relocatable (ie. it never performs a FAR jump or reference).

Debug wouldn't work, so I downloaded debugx, but that didn't work, either.

You might be misunderstanding some basic things here. Do this:

1. Get your code into a raw binary file (ie. code.bin). No ELF, no other formats, just the raw code like it is in your EEPROM.
2. Download debugx
3. Get both your code file and debugx into an emulator such as dosbox.
4. run "debugx code.bin".

debug/debugx will then load the file into memory and set CS:IP to the start of it, then wait for commands. If your code does not enforce references to a specific segment (at 2K, I would certainly hope it doesn't), then you can trace/examine your code this way.
 
If your code does not enforce references to a specific segment (at 2K, I would certainly hope it doesn't),

Actually, thinking about it, most boot ROMs probably do. The reason is that (on 8088/8086) the reset vector is FFFF:0000, so only the last 16 bytes of the ROM will be accessible from the initial code segment. Therefore, boot ROMs usually start with a far jump to some other segment (FF80:0000 would be appropriate for a 2kB ROM). On a 286 or later the initial IP is FFF0 so the ROM could start with a near jump.

However, if you're not worried about debugging that initial instruction, the rest of the ROM can be relocatable (e.g. if part of the ROM is static data then you might want to set up DS with "mov ax,cs / mov ds,ax" instead of "mov ax,0xff80 / mov ds,ax"). If the initial far jump is to offset 0x0100 in the appropriate segment (which would be 0xff70 in this case) then the same raw ROM image could also be a .com file (although presumably one that never returns control to DOS).
 
Alright, I may be getting somewhere. By accident, I think I'm making progress. According to nasm -hf, bin is the default output format, so I had been leaving out the explicit format. However, I just now ran nasm -f bin timeloop.asm. I then tried that in debug, and debug did NOT complain for once. I'm even more baffled now (as if I wasn't before), but I'm going to try messing with debug now to see what I find out. Leave it to me for weird things to happen to :confused:

Chuck, I was actually just replying to your comment about why debug wasn't working, basically just saying I don't know, when I decided to try specifying bin explicitly. I'm so grateful you guys are so willing to help. :)

Now I just have to see if it really is working with debug lol.
 
My go-to 8088 debugger lately has been the one built in to DOSBox (http://www.vogons.org/viewtopic.php?f=32&t=7323). The oldskool, hardware way to debug a boot ROM would have been to use an expensive (and probably hard-to-find, now) in-circuit-emulator that replaces the CPU. Nowadays it's probably much easier to use a software-based emulator. As you correctly surmised, the first problem is going to be persuading whatever emulator you use to load the ROM image and run it in the appropriate way.

First question: if your ROM is loaded into a different segment (but at the correct offset within that segment) do you expect it to work properly? If so, then your job is much easier - you can just write a little .com file stub that loads the ROM image and jumps to the appropriate address, then start the debugger with that.

If the ROM will only work at FF80:0000 then your best bet may be to modify an emulator to load your ROM instead of its own BIOS and recompile it. DOSBox isn't super difficult to modify and recompile (especially on Linux).

As for the problem of emulating your custom hardware instead of a vanilla IBM PC, again this seems like a problem that's quite solvable by modifying DOSBox. If it's just a matter of removing hardware or moving some things around in the memory (or port IO address, or IRQ, or DMA) map, those should be pretty easy changes to make. If your hardware has some peripherals that the emulator doesn't currently emulate then you'll just have to write your own emulations of those peripherals and integrate them, which is a bit more work but may very well end up saving you time in the long run.

I'd advise against trying to compile your ROM into an ELF binary - that's a rabbit hole and doesn't actually solve the real problem of persuading an emulator to load your ROM file at the correct address and run it in the correct way.

Thanks, I hadn't thought about modifying an emulator and recompiling it. That's a good idea! I'm far from a master at assembly and segments and stuff, so I'm learning as I go. But the 8088/86 sets CS to FFFF and IP to 0000, so I don't think loading the ROM into a different segment will work, actually I don't know how it can. And I also hadn't thought about using a .COM file to load the ROM.

And about the ELF, that's exactly what I thought, too. I like your ideas about modifying an emulator.
 
But the 8088/86 sets CS to FFFF and IP to 0000, so I don't think loading the ROM into a different segment will work, actually I don't know how it can.

The idea is this: if your program is started as a boot ROM, the CPU will start it at FFFF:0000 (16 bytes before the end of the image), which does a jump to FF70:0100 (the beginning of the image). When it's started as a .com file, DOS loads it at xxxx:0100 (for some unknown segment xxxx depending on what version of DOS is being used and what drivers, TSRs etc. are loaded) and starts it there.

Almost all instructions work relative to a particular segment, not an absolute physical address. So many programs would work just the same regardless of exactly what segment (RAM or ROM) the program is started at.

Now, writing a boot ROM is a bit more complicated than writing a .com file because you have to do your own initialization of any hardware that you use (e.g. DMA controller and PIT for DRAM refresh) and you have to set up your own stack and non-constant data somewhere in RAM. A boot ROM would probably want to set up the stack at some constant address range. For any address range that you pick, some DOS system somewhere is going to be using those addresses. So when run as a .com file the program needs to disable interrupts and avoid returning to DOS because if it did the system would likely crash due to important OS structures having been overwritten by your stack.
 
So when run as a .com file the program needs to disable interrupts and avoid returning to DOS because if it did the system would likely crash due to important OS structures having been overwritten by your stack.

When DOS starts a .COM file, CS=DS=ES=SS, and SP is set to FFFE. So as long as there isn't a stack overrun, no DOS structures will be harmed, although at the very end of the stack is the PSP, which has the bytes CD 20, so if you do indeed overwrite that then RET will not exit to DOS and you'll have to call the INT 20h yourself to exit back to DOS. But you won't crash DOS as long as you don't touch any segment register.
 
When DOS starts a .COM file, CS=DS=ES=SS, and SP is set to FFFE.

Right, but that isn't the case when the program is run as a boot ROM. So it needs to set up the stack manually for the boot ROM case (unless the CPU's initial values happen to be suitable). I suppose the program could detect whether it's running as a .com or a boot ROM and then have different code paths, but that kind of defeats the point of using this for debugging the boot ROM case (you want the two situations to be as similar as possible).
 
That's good to know about disabling the interrupts. And btw, debug is working now. I almost face-palmed because the reason debug wasn't working before wasn't because of the output file from nasm. The problem was that after all these years of not using DOS, I had forgotten about the 8.3 filename convention. I renamed a file to a shorter name out of pure laziness, but it turned out the length of the filename was the problem! LOL I had overlooked the most basic thing.

In dosbox CS is 06ba. Thanks for your help guys! This should help me a lot going forward! :D
 
Last edited:
Right, but that isn't the case when the program is run as a boot ROM. So it needs to set up the stack manually for the boot ROM case (unless the CPU's initial values happen to be suitable). I suppose the program could detect whether it's running as a .com or a boot ROM and then have different code paths, but that kind of defeats the point of using this for debugging the boot ROM case (you want the two situations to be as similar as possible).

I ended up having to hardcode a far jump at the reset vector because no matter where I tried to ORG the program, it was still loaded at 06ba:0100. I did do:
Code:
-m 8f0 8ff ffff:fff0
to copy the start-up instructions to the real place they would be, and then I did
Code:
-g=ffff:fff0

and it seems to be working fine as I step through it.
 
One problem debugging ROM code is that you cannot use breakpoints. When you set a breakpoint at a certain address, the debugger replaces that address contents with byte C0h (INT 3h). Then the 8088 executes the code an reaches a C0h byte, executes an INT 3h, which is handled by the debugger.
When code is in ROM, the debugger can't write a C0h byte there, and the 8088 will never stop there. I'm not saying that's the reason you can't debug ROM code, but it's something to consider.

You can still use the step-by-step mode, but not use breakpoints.
 
I ended up having to hardcode a far jump at the reset vector because no matter where I tried to ORG the program, it was still loaded at 06ba:0100.

Yes, ORG is an instruction for the assembler, not for the loader (a .com file doesn't have any metadata - it's just loaded into RAM and execution started from the beginning - the initial offset of 0x0100 is implied). You do need to make your ORG correspond to the actual offset after loading, or instructions that reference a an address not relative to the instruction pointer will use the wrong address.

I did do:
Code:
-m 8f0 8ff ffff:fff0
to copy the start-up instructions to the real place they would be, and then I did
Code:
-g=ffff:fff0

and it seems to be working fine as I step through it.

ffff:fff0 corresponds to physical address 0x0ffe0 (just below the 64kB boundary) or 0x10ffe0 (over the 1MB boundary) on a 286 or later CPU - is that what you meant to do? The start point of a boot ROM is FFFF:0000 or F000:FFF0 (both correspond to physical address 0xffff0 - just below the 1MB boundary). Your emulator may not let you write there though...
 
One problem debugging ROM code is that you cannot use breakpoints. When you set a breakpoint at a certain address, the debugger replaces that address contents with byte C0h (INT 3h). Then the 8088 executes the code an reaches a C0h byte, executes an INT 3h, which is handled by the debugger.
When code is in ROM, the debugger can't write a C0h byte there, and the 8088 will never stop there. I'm not saying that's the reason you can't debug ROM code, but it's something to consider.

You can still use the step-by-step mode, but not use breakpoints.
Thanks, that's good to know
 
Yes, ORG is an instruction for the assembler, not for the loader (a .com file doesn't have any metadata - it's just loaded into RAM and execution started from the beginning - the initial offset of 0x0100 is implied). You do need to make your ORG correspond to the actual offset after loading, or instructions that reference a an address not relative to the instruction pointer will use the wrong address.
Ok, that would explain it lol

ffff:fff0 corresponds to physical address 0x0ffe0 (just below the 64kB boundary) or 0x10ffe0 (over the 1MB boundary) on a 286 or later CPU - is that what you meant to do? The start point of a boot ROM is FFFF:0000 or F000:FFF0 (both correspond to physical address 0xffff0 - just below the 1MB boundary). Your emulator may not let you write there though...
You are right. I meant to do FFFF:0000. It was late and I went to bed shortly afterward.
 
Yes, ORG is an instruction for the assembler, not for the loader (a .com file doesn't have any metadata - it's just loaded into RAM and execution started from the beginning - the initial offset of 0x0100 is implied). You do need to make your ORG correspond to the actual offset after loading, or instructions that reference a an address not relative to the instruction pointer will use the wrong address.4
You're saying ORG needs to be the offset, so if I do a far jump to FF80:0000, then ORG should be 0 right? Or did you mean the scenario for when it's being run under DOS debug at 100?
 
You're saying ORG needs to be the offset, so if I do a far jump to FF80:0000, then ORG should be 0 right?

Right. (The far jump needs to start at address FFFF:0000 or 16 bytes before the end of the file).

Or did you mean the scenario for when it's being run under DOS debug at 100?

In that case, ORG 100h is the right value (and is probably the default, especially if outputting a .com file).

And if your far jump is to FF70:0100 then "ORG 100h" will be right for both.
 
Back
Top