Paul, Noel did a great job of explaining the C calling conventions. I'm going to see if I can add a little color, mostly to help explain why. FWIW: Page 115 of the 1979 PDP-11 Processor Handbook has a nice picture and explanation, which I have attached (but I'm not sure if it will pass through the mailing list filters): [image: JSR-Instruct.png] A simple way to think about it is that in C, with an HW-based stack usually r6 (not all systems had an HW-based sp), the >>caller<< maintains the save area. The sp is always pointing to a place that it can write. Thus no need to pop the last item off the stack (*i.e.* first pushed - which in this case means overwriting the top of the stack) since it will also be overwritten when the sp is used later. In your example [I added the LXX and LYY for later explanation]: L2:mov $L4,(sp) jsr pc,*$_printf mov $1,_a mov $2,_b mov $3,_c LXX:mov _c,(sp) mov _b,-(sp) mov _a,-(sp) mov $L5,-(sp) LYY:jsr pc,*$_printf add $6,sp mov $L6,(sp) jsr pc,*$_printf L3:jmp cret So, to map it to the DEC example... the first mov $L4,(sp) at label L2 is putting 'mmmmmm' on the stack, then the immediately following jsr puts the return [which uses an implied pre-decrement, before it writes the stack]. After printf returns (RTS instruction in printf), the sp is back pointing to the same 'top' as it was before the call, so no need to further mess with sp, caller has done nothing other than modify the top of the stack [mov $L4,(sp)]. But then starting at LXX we see 4 mov instructions in row, 3 which modify the sp. This means the caller has 'pushed 6 bytes to the top of stack [downward on a PDP-11 -- via the last three mov's to the stack with the pre-decrement push's], so the caller needs to clean up those 6 bytes that it pushed, with the add the follows the jsr. Note that the next printf's argument is placed on the top of the stack but since not other args are pushed (as with the first call), there is not need to clean up the sp when we return. Clem BTW: If you look at the processors, like the IBM S/360 which lacks an HW stack, and other languages (say Fortran), the '*push down save area*' is maintained by the callee. There is a different convention on where to find parameters for those machines and languages. It's interesting that if you talk to the designers of same (which I have in a number of cases) the 8 and 16 bits microprocessors (*e.g.* 8080/M6800/M6502, 8086/M68000) were most heavily influenced by the S/360 and the PDP-11. It's interesting what features they took from each. Having programmed in both systems (including assembler in both), the PDP-11 stack scheme is much more natural to me personally, but I did spend a number of years in an IBM shop hacking TSS/360 in assembler before I ever saw UNIX. ᐧ On Mon, Jun 28, 2021 at 7:28 AM Paul Riley wrote: > Noel, > > Thanks for that. > > As a non-C consumer of printf, should I point R5 at some space for a stack > and call printf in the same manner as the C example I cited? If it's all > too hard I'll stick to writing to stdout with my own routines. > > Paul > > *Paul Riley* > > Email: paul@rileyriot.com > > > > > On Mon, 28 Jun 2021 at 14:49, Noel Chiappa > wrote: > >> > From: Paul Riley >> >> > I want to use printf from an assembly language program, in V6. ... >> the >> > substitutional arguments for printf are pushed onto the stack in >> reverse >> > order, then the address of the string, and then printf is called. >> After >> > this, 6 is added to the stack pointer. >> >> This is all down to the standard C environment / calling sequence on the >> PDP-11 (at least, in V6 C; other compilers may do it differently). Calls >> to >> printf() are in no way special. >> >> Very briefly, there's a 'frame pointer' (R5) which points to the current >> stack >> frame; all arguments and automatics are relative to that. A pair of >> special >> routines, csv and cret (I couldn't find the source on TUHS, but it >> happens to >> be here: >> >> http://ana-3.lcs.mit.edu/~jnc/tech/unix/lib/csv.s >> >> if you want to see it), set up and tear down the frame on entry/exit to >> that >> routine. The SP (R6) points to a blank location on the top (i.e. lower >> address; >> PDP-11 stacks grow down) of the stack. >> >> To call a subroutine, the arguments are pushed, the routine is called >> (which >> pushes the return PC), and on return (which pops the return PC), the >> arguments >> are discarded by the caller. >> >> (I wrote a note, BITD, explaining how all this worked; I'll upload it to >> the >> CHWiki when I get a chance.) >> >> >> > I assume that the printf routine pops the address of the string off >> the >> > stack, but leaves the other values on the stack >> >> No, all C routines (including printf()) leave the stack more or less >> alone, >> except for CSV/CRET hackery, allocating space for automatic variables on >> routine entry (that would be at L1; try looking at the .s for a routine >> with >> automatic variables), and popping the return PC on exit. The exception to >> this >> is the stuff around calling _enother_ routine (sketched above). >> >> Another exception is alloca() (source here: >> >> http://ana-3.lcs.mit.edu/~jnc/tech/unix/lib/alloca.s >> >> again, couldn't find it in TUHS), which allocated a block of memory on >> the stack (automatically discarded when the routine which called alloca() >> returns). Note that since all automatic variables and incoming arguments >> are relative to the FP, alloca is _really_ simple; justs adjusts the >> SP, and it's done. >> >> > What troubles me is that the stack pointer is not decremented >> before the >> > first mov, in the example below. Is this some C convention? I would >> > assume that the first push in my example would overwrite the top of >> the >> > stack. >> >> That's right; that's because in the C runtime environment, the top >> location >> on the stack is a trash word (set up by csv). >> >> > I understand db only works on files like a.out or core dumps. If I >> > wanted to break the assembly language program to examine values, >> how can >> > I force a termination and core dump elegantly, so I can examine some >> > register values? >> >> Use 'cdb': >> >> https://minnie.tuhs.org//cgi-bin/utree.pl?file=V6/usr/man/man1/cdb.1 >> >> which can do interactive debugging. >> >> Noel >> >