[HN Gopher] Programming with DOS Debugger (2003)
___________________________________________________________________
Programming with DOS Debugger (2003)
Author : susam
Score : 101 points
Date : 2024-04-06 08:46 UTC (2 days ago)
(HTM) web link (susam.net)
(TXT) w3m dump (susam.net)
| M95D wrote:
| I liked the Hello World program = 17 bytes. 13B is just the text
| to print.
| userbinator wrote:
| _The fact that this debugger program is always available with MS-
| DOS or Windows 98 system means that these systems are ready for
| some rudimentary assembly language programming without requiring
| any additional tools._
|
| PC magazines from the 80s through the 90s took advantage of this,
| publishing listings of "source code" that could be typed into
| DEBUG to create tiny but useful utilities, mostly under 1K in
| size. It was an era when "power users" or even moderately
| advanced users would often know some actual programming too and
| many grew into full-time developers; a stark contrast from these
| days when many "real" developers barely understand anything about
| their environment (and are incentivised not to.)
| frogulis wrote:
| > and are incentivised not to
|
| Could you elaborate on that?
| bitwize wrote:
| Not much time for in-depth learning when you have sprint
| commitments to make. Just have Copilot generate the
| boilerplate and tests and fix them as you go.
| snvzz wrote:
| Or copy-paste from stackunderflow.
| exe34 wrote:
| Gotta keep that velocity up!
| 13of40 wrote:
| Example: Everyone knows how to use a Dictionary. It's not
| worth anyone's time to know how it works under the hood,
| because only a fool would actually implement one from scratch
| in production code. Niche embedded cases possibly excepted.
| kqr wrote:
| I would argue this is because we've raised the bar for what
| counts as a computational primitive, and not a qualitative
| difference.
|
| A modern developer can ignore the details of a dictionary
| in the exact same way a programmer of the past could ignore
| the details of the mov instruction. (And be more productive
| for it.)
| ale42 wrote:
| The problem is when developers having virtually no
| background in actual computer science (e.g. algorithm
| complexity) start implementing their own algorithms
| because what thy want is not directly available as a
| primitive. I have the impression that this tendency to
| use more and more complex software primitives, while at
| the same time introducing further levels of indirection
| in the actually run machine code, is one of the reasons
| that many applications are now as slow (or slower) than
| they were 10 years ago despite the hardware being much
| faster. Just compare the performance of an Electron-based
| application (which seems the go-to solution of most
| developers nowadays for desktop app implementation) with
| a native one...
| kqr wrote:
| I think you're embedding a value judgment in this (slow
| execution = bad) that is probably not shared by the
| people using the primitives you think are inappropriate.
|
| In other words, when people don't care for speed they use
| Electron. What part of that indicates that people have no
| background in algorithm complexity? We have traded off
| run-time speed against other things for ages -- even in
| computing science.
| ale42 wrote:
| > I think you're embedding a value judgment in this (slow
| execution = bad) that is probably not shared by the
| people using the primitives
|
| Can be... because I'm also a user, and it's frustrating
| to have the PC bloated by dozens of Electron-based apps
| using huge amounts of RAM, draining the battery more than
| necessary, and for part of them, actually slow to use.
| Perhaps some users don't care because they are either not
| sensitive to small delays or resource usage, or because
| they have never seen anything else.
|
| I see also an environmental question arising here. More
| CPU cycles = more energy used. Makes no difference for
| applications used by small groups of people, but for
| software used in millions of copies, I'm wondering how
| many MWh we are wasting (I wouldn't care much --except
| for battery life-- if energy was only from renewable
| sources... but it's not the case)
| ehaliewicz2 wrote:
| I'm guessing, just guessing, that most of the people who
| don't think slow execution is bad are probably not that
| interested in what the machine actually has to do to
| execute their code, and hence, are not actually well
| educated in making those tradeoffs.
| skissane wrote:
| > It's not worth anyone's time to know how it works under
| the hood
|
| Knowing (at a high level) how your programming language
| implements dictionaries has relevance to questions like
| time complexity of various operations, potential security
| vulnerabilities (a hash table might succumb to hash
| collision denial of service, especially if the
| implementation isn't hardened against that possibility; a
| tree-based implementation probably won't have that
| vulnerability), likely impact of different bugs (e.g. a
| buggy hash method can cause much more problems on a hash
| table than on a tree, while for a buggy comparison method
| it is the other way around), concurrency, etc
|
| > because only a fool would actually implement one from
| scratch in production code
|
| I've implemented a dictionary before in C. Not for work
| (only wrote C code for work one single time ever, and it
| was only a page worth of code that was called from Java, no
| complex data structures needed), just for my own
| learning/amusement. That said, C is probably the one
| context in which people still commonly "roll their own"
| basic data structures, even in production code, just
| because C's standard library is so weak in that regard (and
| C's lack of generics/templates doesn't help either)
| commandlinefan wrote:
| > only a fool would actually implement one
|
| No, only a fool would let his boss know that he did.
| boffinAudio wrote:
| You need permission to write software and distribute for
| modern platforms. This is very disincentivizing .. not so
| when you've got a compiler/assembler onboard everywhere and
| can just ship without permission from MegaCorp...
| GuB-42 wrote:
| You are incentivized to user higher abstractions, sometimes
| for good reasons (portability, productivity, etc...).
|
| But the higher you go, the more magic there is. On a DOS
| machine when x86 processors actually ended with "86", or on
| home computers like C64s and Amigas, everything was simple.
| No concurrency, no security, no networking, you had a
| processor and it ran instructions. You go from a character
| displayed on screen and with a little research, have a good
| idea about everything that happened down to the transistor.
| Now, it is impossible, most of the hardware components of a
| modern computer are made of little computers, each one orders
| of magnitude more complex than these early systems, many of
| them run encrypted software.
|
| It means that now, software development is more about trying
| to get an idea of what the people who made the layer under
| yours were thinking about. It is becoming harder to go with
| first principles, too complex, it is therefore discouraged,
| as it is more likely to hurt productivity.
| commandlinefan wrote:
| > "source code" that could be typed into DEBUG
|
| Oh, wow - I remember doing something similar on my Commodore
| 64. The C64 came with a BASIC interpreter, but no built-in
| assembler. There was a magazine called Compute's Gazette that
| included, in the back of every issue, a simple assembler of
| sorts written in BASIC. So if you wanted to run any of the
| programs included in the magazine, you'd first type in the code
| for the assembler and use that to "bootstrap" your assembler
| programs. They were long (pages and pages) of listings of
| hexadecimal, with a checksum at the end of each line to make
| sure you didn't make a tiny mistake toward the beginning that
| rendered the whole thing useless.
|
| It was actually pretty amazing how sophisticated some of these
| programs would end up being, considering the entire hex dump
| could realistically be printed on four or five A4 standard
| pages.
|
| Man, I spent a lot of time typing those things in - I still
| remember off the top of my head, almost 40 years later, that
| the opcode for LDA was A9 and STA was 8D, because I typed those
| in a _lot_. Back then, I thought that this was more or less
| what a career in computer programming would be like - honestly,
| with the JIRA tickets and Sprint retrospectives and standups
| and planning sessions that it's turned out to be, I'm a little
| disappointed.
| kazinator wrote:
| I once made a tiny pre-emptive kernel using the DOS debugger. It
| was like the day after graduating from CS undergrad, and I needed
| a cleanse from the many years-long C on Unix mission (which
| happens to be continuing, decades later).
| dleslie wrote:
| I still have a copy of "Assembly language step-by-step" which
| started with DEBUG then moved to nasm in later chapters.
| Zardoz84 wrote:
| I have yet a book of Peter Norton of 80286 assembly that uses
| DEBUG a lot to do the first steps programming assembly.
| hyperdimension wrote:
| Funny that this would come up today; I'm working through that
| very book now. I'm still in the debug part and using 'a'
| though; I haven't moved onto the assembler yet.
| EvanAnderson wrote:
| Debug is a passable quick-and-dirty assembler. It's no fun to
| refactor code after you've resolved all the addresses and hard-
| coded them into the "source" but when you're in a pinch and don't
| have access to real tools it works well.
| netmare wrote:
| I "solved" that by using two assembling passes. The first had
| dummy jump/call addresses in order to determine the code
| offsets of labels. Then I would resolve the relative offsets,
| replace the target labels with offset deltas and reassemble.
|
| I used that trick to speed up my QBasic programs with graphics,
| string and list handling, etc. It was one of the first
| rewarding times in my programming "career" and it actually made
| me feel proud of myself.
| EvanAnderson wrote:
| Yeah-- I did the same thing. It just sucks when you've
| forgotten s prefix or a push/pop early in the code and you
| have to retarget all the subsequent addresses. It really
| makes you appreciate a real assembler.
| 48864w6ui wrote:
| If you write basic blocks only with a certain alignment there's
| much less hand patching imposed for small changes
| EvanAnderson wrote:
| I remember reading about people doing that on the Apple II
| with the Woz mini assembler. I always had an assembler on the
| 6502 so I never did it myself. Makes sense though. Never
| thought to do it on x86 but it's a good idea.
| userbinator wrote:
| After a while, you get really good at hex arithmetic and
| memorising x86 instruction lengths.
| peter_d_sherman wrote:
| A few things to point out:
|
| 1) The Debugger and the program being debugged -- are effectively
| running in the _same execution environment_ ; the _same memory
| space_ (both programs are different ranges of the same memory and
| both can access each other 's memory without restrictions, but
| only one can be running at one time (single stepping swaps
| control (for an instant) and then swaps it back again, as does
| running under the debugger until a breakpoint is hit -- as there
| are absolutely NO threads (concurrent code execution paths) in
| this environment!)
|
| If the debugged program crashes for any reason, for example,
| enters an infinite loop and/or doesn't yield control back to the
| debugger via executing a RET instruction -- then the entire PC
| (if DOS is running directly on hardware (as opposed to under
| Windows and/or a VM) will crash, AKA "lock-up"! Powering the
| entire machine on and off is now necessary to reboot it! (Dave
| Letterman, many years ago, in response to the then-feared
| upcoming Y2K disaster: "Just Reboot!")
|
| 2) While this mode of programming is hard, laborious, counter-
| intuitive, slow, and error-prone(!) -- it should also be _lauded,
| praised_ -- because equal-and-oppositely, whoever is programming
| at this level has effectively _gotten rid of 99.99% of the "tech
| stack" dependencies_ -- the code written by other programmers in
| compilers, operating systems, programing languages, programming
| environments, libraries, frameworks, tech stacks, other software
| components, etc., etc.
|
| Oh sure, there's still DOS in the background... but the DOS
| code/API fits into like what, like 32KB? (That's Kilobytes with a
| 'K', not Megabytes or Gigabytes... several orders of magnitude
| smaller...)
|
| And a pure assembly low-level programmer -- does not even need to
| depend/rely on DOS or BIOS calls... they can effectively get rid
| of those too by writing their own hardware drivers... OS
| developers that write in Assembly typically do this or something
| like this...
|
| Anyway, an excellent article!
| rahen wrote:
| DOS makes a nice runtime for low level and embedded
| applications. Some implementations are 64 bits, such as this
| one: https://github.com/dosemu2/fdpp
|
| I wish there were an ARM-compatible version of DOS, if possible
| stateless. It would often be more suitable for an ARM board
| than a full-fledged Linux, given its almost non-existent attack
| surface, low resource consumption, and simplicity. Heck, I'd
| even like to see DOS microservices on stateless nano-VMs.
| 082349872349872 wrote:
| > _whoever is programming at this level has effectively gotten
| rid of 99.99% of the "tech stack" dependencies_
|
| Not necessarily: I once worked with a team whose reference
| manual was the S/360 "Principles of Operation" -- but they
| weren't exactly working on the metal; everyone's model of the
| 360 architecture was virtual, all running on top of a (1960's!)
| supervisor multiplexing the actual box.
|
| https://en.wikipedia.org/wiki/Conversational_Monitor_System
|
| http://bitsavers.trailing-edge.com/pdf/ibm/360/princOps/A22-...
| tommieb wrote:
| Lovely article, that brought back memories! A wee pedantic bit
| here, to exit the program, it was the school of thought, to use
| the following instruction - set the exit code to zero and issue
| terminate.
|
| mov ah, 4ch mov al, 00h ; Or combine both mov into mov ax, 4c00h
| int 21h
| keepamovin wrote:
| This is where I first learned to program. the manual for MS-DOS
| 3.1 I think it was came with instructions for the debugger and
| assembler, and how you could create programs.
| boffinAudio wrote:
| I once made a lot of money by guiding a colleague over the phone
| how to write a program with DEBUG.com to do a software 'upgrade'
| consisting of 128 bytes to change in the older version .. this
| was pre-Internet-everywhere, and the time cost of waiting for a
| tape (yes we delivered DOS software on tape back in the day) to
| arrive across country was too high. An hour of careful hex
| narration later, we got it done and days of downtime were saved.
| Oh, what a bonus that was (went straight into a new 486, lol).
|
| Kind of miss DEBUG.com now that I think about it.
| _0ffh wrote:
| I'm sure I'm not the only one who's learned to write 6502
| assembly on a machine code monitor [1].
|
| [1] https://www.c64-wiki.com/wiki/Machine_Code_Monitor
| jim_lawless wrote:
| DEBUG was also able to read/write disk blocks and it could load /
| save files from memory based on register settings. I had written
| a batch file and a file of DEBUG commands ( redirected into DEBUG
| ) that would load the blocks from 1.44M diskettes at about 64K at
| a time, save each just-under-64k segment with a separate
| filename, and then zip up the whole collection. I also had
| written the counterpart scripts to decompress and block-write the
| data back out to a 1.44M floppy. This allowed us to archive the
| .zip collections as disk images for some critical boot disks and
| such.
|
| I had also written a utility in C published in Windows/DOS
| Developer's Journal (April 1995) before some email clients could
| UUDECODE or Base64-decode attachments. This utility wrote a short
| loader as a text file followed by the G command to execute it.
| Following the G command were lines of UUENCODED data. The
| assembly language loader code would begin reading lines from the
| standard input device and would UUDECODE them as it added them
| into DEBUG's current working buffer starting at 100h. At the tail
| end of the script, the N command was used to name the output
| file, the CX register was updated via RCX to set the output
| length, and the W command was used to save the file. This allowed
| me to send some encoded binary files embedded in the body of the
| email to folks that didn't have sophisticated email clients. They
| could just pipe this portion of the email into DEBUG and it would
| ultimately write the decoded binary file.
| anthk wrote:
| Your solution it's similar to sharutils.
| billpg wrote:
| My 80s era BBC Micro came with a 6502 assembler as part of BASIC
| built into ROM.
|
| It was a little quirky in that it was a two-pass assembler only
| if you put it inside a FOR loop and turned off unknown-identifier
| errors on the first pass. I was told you could write rudimentary
| assembler macros with judicious use of PROC but I could never get
| it working.
| fuzztester wrote:
| You could easily create a tiny .COM program to reboot the PC,
| using DEBUG.
|
| You had to start DEBUG, then, at its prompt, use, in sequence,
| the A (Assemble) command to assemble a JMP instruction, the N
| (Name) command to name the .COM file to write the assembled
| machine code to, the R (Register) command to set the CX register,
| indicating the number of assembled machine code bytes to write to
| the file (with the BX register already initialised to 0 by DEBUG
| on startup, because both BX and CX were used to indicate the
| number of bytes to write) and then the W (Write) command to write
| that many bytes of machine code to that file.
|
| Then you would exit DEBUG.
|
| Now, at any time after that, you could run that .COM file to
| reboot your PC.
|
| So if it was called R.COM, you could just type R and hit Enter to
| reboot. (In DOS, you did not have to type the executable file
| name's extension, whether it was .COM or .EXE or .BAT.)
|
| So if you were playing a game in the office during working hours,
| it could be faster to type R and hit Enter, than even to press
| Ctrl-Alt-Del or to press the reboot button of your PC. Useful if
| your boss suddenly came into the room ...
|
| IIRC the JMP instruction was: JMP F000:FFF0. (1)
|
| That would make the PC jump to that address in memory (in the
| BIOS ROM) and start executing the code there.
|
| And that was the start of the BIOS machine code to reboot the PC.
|
| (1) When I googled just now to confirm the address, since I was
| not sure of the exact one, interestingly, the first hit was an
| article about the same topic on ... Susam's site :)
|
| But his BIOS address as shown is different from mine.
|
| See the section "Reboot Program" at:
|
| https://susam.net/rebooting-with-jmp-instruction.html
| fuzztester wrote:
| My second paragraph above only outlines how to do it. It
| assumes that you know the syntax of the DEBUG commands.
|
| Susam's article linked above shows the exact procedure, with
| precise syntax.
| fuzztester wrote:
| >So if you were playing a game in the office during working
| hours, it could be faster to type R and hit Enter,
|
| Of course, you would have to exit the game first, but many DOS
| games could be exited fast, by just pressing Esc rapidly one or
| more times, or Alt-X, or other similar methods.
| fuzztester wrote:
| The .COM program was only 5 bytes long, so it loaded instantly
| too.
| philkrylov wrote:
| Actually, using DEBUG for creating anything besides one or two
| simple DOS/BIOS calls was a PITA due to the lack of symbolic
| labels. After that, the MASM/TASM boilerplate started to feel
| bearable.
___________________________________________________________________
(page generated 2024-04-08 23:02 UTC)