The Unix Heritage Society mailing list
 help / color / mirror / Atom feed
* [TUHS] Using printf from Assembly Language in V6, and db.
@ 2021-06-28  2:34 Paul Riley
  2021-06-28  3:27 ` Paul Riley
  0 siblings, 1 reply; 7+ messages in thread
From: Paul Riley @ 2021-06-28  2:34 UTC (permalink / raw)
  To: tuhs

[-- Attachment #1: Type: text/plain, Size: 1918 bytes --]

Hi,

I want to use printf from an assembly language program, in V6. It seems
that the Unix Programmer's Manual doesn't show how to use it from assembly,
so I wrote a short C program and captured the assembler output, for some
clues. Listings below.

In my example, 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. I assume that the
printf routine pops the address of the string off the stack, but leaves the
other values on the stack, hence the need to add 2x3=6 to the stack after
calling printf in my example.

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.
Perhaps I'm not used to PDP-11 stack conventions.

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?

Paul


*Paul Riley*

Email: paul@rileyriot.com

int a, b, c;
int main(){
  printf("printf: start\n");
  a = 1;
  b = 2;
  c = 3;
  printf("A = %d, B = %d, C = %d", a, b, c);
  printf("printf: end\n");

}

.comm   _a,2
.comm   _b,2
.comm   _c,2
.globl  _main
.text
_main:
~~main:
jsr     r5,csv
jbr     L1
L2:mov  $L4,(sp)
jsr     pc,*$_printf
mov     $1,_a
mov     $2,_b
mov     $3,_c
mov     _c,(sp)
mov     _b,-(sp)
mov     _a,-(sp)
mov     $L5,-(sp)
jsr     pc,*$_printf
add     $6,sp
mov     $L6,(sp)
jsr     pc,*$_printf
L3:jmp  cret
L1:jbr  L2
.globl
.data
L4:.byte 160,162,151,156,164,146,72,40,163,164,141,162,164,12,0
L5:.byte
101,40,75,40,45,144,54,40,102,40,75,40,45,144,54,40,103,40,75,40,45,144,0
L6:.byte 160,162,151,156,164,146,72,40,145,156,144,12,0
#

[-- Attachment #2: Type: text/html, Size: 2670 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [TUHS] Using printf from Assembly Language in V6, and db.
  2021-06-28  2:34 [TUHS] Using printf from Assembly Language in V6, and db Paul Riley
@ 2021-06-28  3:27 ` Paul Riley
  0 siblings, 0 replies; 7+ messages in thread
From: Paul Riley @ 2021-06-28  3:27 UTC (permalink / raw)
  To: tuhs

[-- Attachment #1: Type: text/plain, Size: 2688 bytes --]

Or perhaps...

In my example, 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. I assume that the
> printf routine pops the address of the string off the stack, but leaves the
> other values on the stack, hence the need to add 2x3=6 to the stack after
> calling printf in my example.
>

... just adding 2 for every decrement that was done on sp...

Paul

*Paul Riley*

Mo: +61 (0)411 781 394
Email: paul@rileyriot.com



On Mon, 28 Jun 2021 at 12:34, Paul Riley <paul@rileyriot.com> wrote:

> Hi,
>
> I want to use printf from an assembly language program, in V6. It seems
> that the Unix Programmer's Manual doesn't show how to use it from assembly,
> so I wrote a short C program and captured the assembler output, for some
> clues. Listings below.
>
> In my example, 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. I assume that the
> printf routine pops the address of the string off the stack, but leaves the
> other values on the stack, hence the need to add 2x3=6 to the stack after
> calling printf in my example.
>
> 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.
> Perhaps I'm not used to PDP-11 stack conventions.
>
> 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?
>
> Paul
>
>
> *Paul Riley*
>
> Email: paul@rileyriot.com
>
> int a, b, c;
> int main(){
>   printf("printf: start\n");
>   a = 1;
>   b = 2;
>   c = 3;
>   printf("A = %d, B = %d, C = %d", a, b, c);
>   printf("printf: end\n");
>
> }
>
> .comm   _a,2
> .comm   _b,2
> .comm   _c,2
> .globl  _main
> .text
> _main:
> ~~main:
> jsr     r5,csv
> jbr     L1
> L2:mov  $L4,(sp)
> jsr     pc,*$_printf
> mov     $1,_a
> mov     $2,_b
> mov     $3,_c
> mov     _c,(sp)
> mov     _b,-(sp)
> mov     _a,-(sp)
> mov     $L5,-(sp)
> jsr     pc,*$_printf
> add     $6,sp
> mov     $L6,(sp)
> jsr     pc,*$_printf
> L3:jmp  cret
> L1:jbr  L2
> .globl
> .data
> L4:.byte 160,162,151,156,164,146,72,40,163,164,141,162,164,12,0
> L5:.byte
> 101,40,75,40,45,144,54,40,102,40,75,40,45,144,54,40,103,40,75,40,45,144,0
> L6:.byte 160,162,151,156,164,146,72,40,145,156,144,12,0
> #
>
>

[-- Attachment #2: Type: text/html, Size: 4168 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [TUHS] Using printf from Assembly Language in V6, and db.
  2021-06-28 20:37 Noel Chiappa
@ 2021-06-29 12:18 ` Paul Riley
  0 siblings, 0 replies; 7+ messages in thread
From: Paul Riley @ 2021-06-29 12:18 UTC (permalink / raw)
  To: Noel Chiappa, Clem Cole; +Cc: tuhs

[-- Attachment #1: Type: text/plain, Size: 1227 bytes --]

Thanks Noel, Clem for your always generous and highly informative answers.
I'll digest that and enjoy using C routines in my assembly programs!

Paul

*Paul Riley*

Email: paul@rileyriot.com




On Tue, 29 Jun 2021 at 06:37, Noel Chiappa <jnc@mercury.lcs.mit.edu> wrote:

>     > From: Paul Riley <paul@rileyriot.com>
>
>     >> (I wrote a note, BITD, explaining how all this worked; I'll upload
> it
>     >> to the CHWiki when I get a chance.)
>
> Now here:
>
>   https://gunkies.org/wiki/PDP-11_C_stack_operation
>
> along with simple examples of args and auto variables, which are both
> referenced via the FP.
>
>
>     > 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?
>
> Not necessary to do anything with R5 (you can leave it blank); the only
> things
> a PDP-11 C routine needs are:
>
> - a good stack
> - the arguments, and return point, on the top of the stack
>
> csv will set up the frame pointer, making no assumptions about the old
> contents of R5 - see the source:
>
>   http://ana-3.lcs.mit.edu/~jnc/tech/unix/lib/csv.s
>
> although it does save the old R5 contents, and restore them on exit.
>
>          Noel
>

[-- Attachment #2: Type: text/html, Size: 2307 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [TUHS] Using printf from Assembly Language in V6, and db.
@ 2021-06-28 20:37 Noel Chiappa
  2021-06-29 12:18 ` Paul Riley
  0 siblings, 1 reply; 7+ messages in thread
From: Noel Chiappa @ 2021-06-28 20:37 UTC (permalink / raw)
  To: tuhs; +Cc: jnc

    > From: Paul Riley <paul@rileyriot.com>

    >> (I wrote a note, BITD, explaining how all this worked; I'll upload it
    >> to the CHWiki when I get a chance.)

Now here:

  https://gunkies.org/wiki/PDP-11_C_stack_operation

along with simple examples of args and auto variables, which are both
referenced via the FP.


    > 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?

Not necessary to do anything with R5 (you can leave it blank); the only things
a PDP-11 C routine needs are:

- a good stack
- the arguments, and return point, on the top of the stack

csv will set up the frame pointer, making no assumptions about the old
contents of R5 - see the source:

  http://ana-3.lcs.mit.edu/~jnc/tech/unix/lib/csv.s

although it does save the old R5 contents, and restore them on exit.

	 Noel

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [TUHS] Using printf from Assembly Language in V6, and db.
  2021-06-28 11:27 ` Paul Riley
@ 2021-06-28 13:48   ` Clem Cole
  0 siblings, 0 replies; 7+ messages in thread
From: Clem Cole @ 2021-06-28 13:48 UTC (permalink / raw)
  To: Paul Riley; +Cc: tuhs, Noel Chiappa


[-- Attachment #1.1: Type: text/plain, Size: 6681 bytes --]

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 <paul@rileyriot.com> 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 <jnc@mercury.lcs.mit.edu>
> 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
>>
>

[-- Attachment #1.2: Type: text/html, Size: 15075 bytes --]

[-- Attachment #2: JSR-Instruct.png --]
[-- Type: image/png, Size: 281905 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [TUHS] Using printf from Assembly Language in V6, and db.
  2021-06-28  4:48 Noel Chiappa
@ 2021-06-28 11:27 ` Paul Riley
  2021-06-28 13:48   ` Clem Cole
  0 siblings, 1 reply; 7+ messages in thread
From: Paul Riley @ 2021-06-28 11:27 UTC (permalink / raw)
  To: Noel Chiappa; +Cc: tuhs

[-- Attachment #1: Type: text/plain, Size: 3451 bytes --]

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 <jnc@mercury.lcs.mit.edu> 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
>

[-- Attachment #2: Type: text/html, Size: 4808 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [TUHS] Using printf from Assembly Language in V6, and db.
@ 2021-06-28  4:48 Noel Chiappa
  2021-06-28 11:27 ` Paul Riley
  0 siblings, 1 reply; 7+ messages in thread
From: Noel Chiappa @ 2021-06-28  4:48 UTC (permalink / raw)
  To: tuhs; +Cc: jnc

    > 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

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2021-06-29 12:19 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-28  2:34 [TUHS] Using printf from Assembly Language in V6, and db Paul Riley
2021-06-28  3:27 ` Paul Riley
2021-06-28  4:48 Noel Chiappa
2021-06-28 11:27 ` Paul Riley
2021-06-28 13:48   ` Clem Cole
2021-06-28 20:37 Noel Chiappa
2021-06-29 12:18 ` Paul Riley

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).