4

When I run a debug session using FreeDOS and DEBUG.EXE, I get a session like the following. I've added a description of what I saw as annotation on the image. Each step, I've printed out the stack contents. What's very confusing is why the stack is changing at all given the commands I am running - such as simple moves between registers.

Step 1: move AX into DS, and mysteriously, something starts eating the stack! what gives?

MOV DS, AX

Step 2: move a literal 0 value into DX, and weirdly a couple values on the stack start to change. Why on Earth is this happening?

MOV DX, 0000

... and so on. Look closely at the image to see how things change from step to step.

If anyone has a clue, I'd love to hear it.

debug session

5
  • 3
    This is probably off-topic here, even if you are using retro tooling.
    – tofro
    May 28, 2018 at 14:20
  • 2
    What's retro about this is the reliance of interrupt service routines on the user's stack. Modern processors tend to have alternative hardware mechanisms for this, such a shadow stack pointer register that is switched to while entering in supervisor mode to service interrupts. From today's point of view, it would be bad form for the OS to have rely on the user program maintaining a proper stack pointer register and adequate stack space for servicing interrupts, given that a modern OS is protecting itself and other processes against malicious or accidental behaviors.
    – Erik Eidt
    May 29, 2018 at 14:14
  • @ErikEidt I don't think that's enough to justify this as a "retrocomputing" question. The reason why this is happening is not "because you are using a retro OS", but because "you cannot rely on the memory below the stack pointer not changing". For example, I can imagine a "modern" OS where if those bytes are in a different page, they could go from "00" to "page not present" in between instructions (I don't know if that can happen in Windows; it would not occur to me to care because "I don't rely on the memory below the SP not changing"). May 30, 2018 at 11:34
  • 1
    Sure, you don't want to rely on memory below the SP in general. However, the OP is not attempting to rely on memory below the SP, but rather understand this observed behavior relative to mere debugging. And I'm asserting that this particular behavior, due to its antiquated interrupt handling mechanism, is a "retro".
    – Erik Eidt
    May 30, 2018 at 15:35
  • @EuroMicelli: Actually, modern PC platforms have made it "officially" safe for a function which doesn't use the stack or call other functions to use up to (IIRC) 512 bytes beyond the stack pointer for local variables without having to adjust SP before and after doing so, and so the fact that such usage isn't safe everywhere is verging on "retro". Further, on most modern debug platforms it is safe for code to abuse the stack pointer while interrupts are disabled, but the design of MS-DOS DEBUG isn't modern.
    – supercat
    Jun 1, 2018 at 19:18

2 Answers 2

12

Note all your references to changing values are below the stack pointer, actually a free space. You are not expected to care about this area (stack grows towards lower addresses), as this is of no concern to your application.

Even if your computer is sitting at a debugger prompt and apparently is inactive, it isn't. It constantly runs through interrupt service routines, like the timer (or other peripherals) interrupt routines that constantly use stack memory, others will be the result of the debugger itself frequently looking for keypresses - What you see is simply the leftovers of these frequent activities in the free space of the stack (which is absolutely irrelevant for your application - The part of the stack your application is working with is above the stack pointer). Thus, the values you see are areas of free space that have been used and changed by such system routines, as you are sharing the stack with these routines. And, BTW, it is absolutely irrelevant what your appliction is doing in a debug step - These areas might also change if you are not even stepping through your own code.

The only thing you hopefully will never observe is values changing at and above the stack pointer or intermittent changes of the stack pointer itself because this is where your program's working memory is.

11
  • I guess I'm just surprised that even in this scenario, it would be necessary for applications to use memory so close to my own. I guess I was thinking it would somehow use more distant memory, sort of "outside" my memory space.
    – Byron Katz
    May 29, 2018 at 19:15
  • @ByronKatz: More modern debugging tools will often avoid disturbing anything near the application's stack, but doing that requires that either the processor has a separate stack pointer for the application and the debugger, or that the debugger emulates the behavior of a virtual CPU, which in the absence of hardware support would totally dog performance [probably by at least an order of magnitude].
    – supercat
    Jun 1, 2018 at 21:02
  • 1
    @supercat this is not so much s function of the debugging tool, but rather of the OS, where the stack is, is normally not determined by the debugger.
    – tofro
    Jun 7, 2018 at 18:52
  • @tofro: Debuggers often virtualize some aspects of system behavior. If the debugger virtualizes the stack, it can put it somewhere that it won't get stomped. On the 8088/8086, the only way a debugger could virtualize the stack would be to emulate instruction execution. Such a thing may be possible, but would be quite expensive. An 80386-specific debugger which is intended for use only with 8086-based code, however, could virtualize the stack much more cheaply.
    – supercat
    Jun 7, 2018 at 19:51
  • 1
    TD386 used virtual mode to be able to use memory above 1M for the debugger code itself (enabling debugging of programs that largely filled DOS memory space, with a close-to-zero footprint of the debugger in conventional memory) - To my knowledge, it had none of the features you mentioned. And, I would still be annoyed if it would move my stack around.
    – tofro
    Jun 8, 2018 at 9:01
1

The cause of this change is the fact that you are using the 't' command to step through instructions. That command makes use of a CPU interrupt to regain control after the instruction completes. That interrupt stores state on the stack before transferring control to the interrupt handler. The state on the stack is what you are seeing.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .