This overlaps with experience with the first Fortran.
About 1957 at Livermore I was rummaging around the filing cabinets for punched cards. I came upon a drawer mostly full of cards with a small deck of binary cards at the front wrapped in a rubber band. The deck in binary starting with a familiar loader and was less than an inch thick; the rest of the cards were symbolic (Hollerith.) There were a few pages of description of a new assembler format that differed considerably from the NYAP that we were using. I guessed that the binary was the assembler proper and that the rest was the source for it. That turned out to be the case.
There are three programmer’s whose code I have found especially rewarding to read:
Fools ignore complexity. Pragmatists suffer it. Some can avoid it. Geniuses remove it.
I was soon able to adapt the assembler for our use; we did not have the source for NYAP. Indeed this was perhaps the first large program I had seen where the output of the assembler would actually run correctly. Debugged programs had generally been patched versions of assembler output. The programmer would patch by punching a few binary commands on a card and adding that to the end of the binary deck from the assembler. He would hopefully annotate the assembler listing so that the same change would be made to the source. The debugging cycle did not afford an assemble step in general. The cost of reading 2000 cards thru a card reader at 150 cards/min and then printing at 75 lines/min made that infeasible. In one (just one) extreme case the programmer threw out the source assuming that he would never be able to afford to assemble it again. Here is a bit more detail on the assembler’s function. A few years later we had facilities to make updates via the card reader to sources kept on a magnetic tape. Printing was off line and so the cost of assemblies became affordable.
A common alternative debug cycle that we developed for the Stretch was to manually annotate the assembler listing, make a corresponding symbolic change deck, or add changes to the one used in the previous debug cycle, bring the symbolic source tape and change deck to the machine and assemble or compile without a new listing. The assembler and compiler listing included line numbers to make preparation of change decks easy. When the annotations became burdensome, a new listing and magnetic tape was made and the change deck was retired and a new one began to grow. The Fortran compiler worked this way too.
For each instruction of the program an assembler listing would include the instruction in binary (octal) and its symbolic source precursor on one line. Some assemblers provided symbolic cross references. Recent assemblers do not produce listings. Debugging was done at a desk away from the computer with an assembler listing and a binary (octal) printout of memory (dump) at the time of the program failure. This was feasible when memory cost one dollar per bit.