1

This is PDP-11 code mixing C and assembly. In the below, u.u_rsav is an array pointer,

savu(u.u_rsav);

The assembly code for this function is

_savu:        bis     $340,PS
              mov     (sp)+,r1
              mov     (sp),r0
              mov     sp,(r0)+
              mov     r5,(r0)+
              bic     $340,PS
              jmp     (r1)

It seems like before it enters the procedure, it first pushes the argument, then pushes the return point PC value. So, r1 stores PC and r0 stores the argument. My puzzle is sp (stack pointer) does not restore to the original value before the assembly code jumps back to the calling point. It still points to the position where the argument was stored in the stack.

fuz
  • 88,405
  • 25
  • 200
  • 352
CCNA
  • 388
  • 7
  • 17
  • 6
    Each architecture has it's own conventions documented in the corresponding ABI. Find one for your case. – Eugene Sh. Mar 14 '18 at 14:54
  • 3
    That *is* the original position before the `call` instruction. C with stack-args calling conventions often uses a caller-pops convention. I'd definitely expect that on PDP-11, because very early C often didn't use prototypes, so the callee could easily pass an extra arg (that the callee wouldn't know to pop) without it being a compile-time error. But caller-pops conventions don't have a problem with that, so they work for `printf` and other variadic functions. – Peter Cordes Mar 14 '18 at 14:57
  • 1
    Besides the ABI mentioned by Eugene Sh., for some CPU architectures the conventions for calling functions and passing parameters may even vary between compiler vendors. – Gerhardh Mar 14 '18 at 15:03
  • Off-topic, since asking for external resources (ABI conventions for PDP11) – Basile Starynkevitch Mar 14 '18 at 17:10

2 Answers2

6

In C, especially K&R C as is likely to be used by any PDP-11 compiler, the called function cannot know how many arguments the calling function placed on the stack. This is how var args functions used to work. For example, printf would be declared in stdio.h like this:

int printf();

And the definition would start like this:

int printf(fmt)

char *fmt;

{
    /* function body */
}

And the caller could then just do (for example)

printf("%d %d\n", a, b);

Thus, it has to be the responsibility of the calling function to remove the arguments from the stack, not the called function.

To make things clearer and that it is not just variadic functions, in K&R C, the following was perfectly legal and would print 3.

int add();

int main()
{
    int sum;
    sum = add(1, 2, 3, 4);
    printf("%d\n", sum);
    return 0;
}

int add(a, b)
int a;
int b;
{
    return a + b;
}
JeremyP
  • 84,577
  • 15
  • 123
  • 161
  • It doesn't *have* to be. But it would mean your program crashed if you got the format string wrong if, `printf` removed args based on what it found in the format string, instead of getting mangled output or silently-ignored args. (BTW, on x86, callee-pops can only be efficient when the number of args to pop is a compile-time constant: `ret 12` for example only works with an immediate, not a register. But PDP11 appears to return with a regular indirect jump, and wouldn't have this problem.) Anyway, there are compelling reasons for caller-pops for variadic functions, and it's common in general. – Peter Cordes Mar 15 '18 at 04:13
  • @PeterCordes It does have to be. `printf` was just an example. In general, in K&R C, the called function has no idea how many arguments the calling function placed on the stack. It could remove the ones it knows about from the definition, but that doesn't mean the calling function didn't put other arguments on the stack as well (that the callee will ignore). – JeremyP Mar 15 '18 at 09:35
  • Right, if you want extra args to be safely ignored, it has to be. But even without prototypes, callers have to pass the args that callees expect. If you restrict things to *only* that subset of C where the caller passes only the args the callee looks at, then callee pops would work. It's brittle, hard to debug when it breaks, and nobody wants that, which is why it's not done in practice. :P – Peter Cordes Mar 15 '18 at 09:38
-1

It is not C, but the Application Binary Interface conventions (you often have several language implementations or compilers following the same ABI, and you did had in the past various compilers with different ABI conventions on the same system). And it is architecture and operating system specific. BTW, calling conventions are part of ABIs.

For examples, see those related to x86

It is up to you to find the ABI conventions for the archeological PDP11 computer (and compiler, and OS), e.g. see PDP11 FAQ and C calling conventions. Some ABIs used the stack, with various caller safe / callee safe conventions on registers.

My puzzle is sp (stack pointer) does not restore to the original value before the assembly code jumps back to the calling point.

Some ABIs or calling conventions require the stack pointer to be restored by the called function. Others want the calling function to do that.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • 2
    This answer does not stand on its own and on top links to an irrelevant ABI supplement. Please amend to actually answer the question or post as a comment instead. – fuz Mar 14 '18 at 16:09
  • 4
    @fuz Well, the question is "how does C program transfer arguments under the hood?" What else is there to say, since this isn't about C, but all about the ABI. I don't know how it would be possible to flesh out the answer more. As for if PDP-11 had caller/callee push-pop etc, I'm sure it is mentioned in RTFM for whatever dinosaur compiler that's needed to compile for that hardware - whoever is interested in software archaeology could go read that themselves. – Lundin Mar 14 '18 at 16:16
  • 2
    Your last addendum reads like “It's up to you to find an answer to your question.” Seems a bit like you missed the point of answering questions on Stack Overflow. – fuz Mar 14 '18 at 17:48
  • No, asking for external resources is off-topic. By googling I found a few – Basile Starynkevitch Mar 14 '18 at 18:18
  • @BasileStarynkevitch OP did not ask for external resources. OP asked for an expanation, which your answer does not provide (links to external resources do not constitute an explanation). – fuz Mar 14 '18 at 20:01