0
\$\begingroup\$

My text (Computer Organization and Embedded Systems, 6e, by Hamacher et al.) poses the following:

Consider the following possibilities for saving the return address of a subroutine:
(a) In a processor register
(b) In a memory location associated with the call, so that a different location is used when the subroutine is called from different places
(c) On a stack

and says that the answer options are:

(a) Neither nesting nor recursion are supported.
(b) Nesting is supported, because different Call instructions will save the return address at different memory locations. Recursion is not supported.
(c) Both nesting and recursion are supported.

I cannot understand the comment regarding (b).

Suppose our solution was (a).

This works for a case where we go "one level deep" but if we nest or recurse then everything except the very last calling function will have the correct returning address clobbered. No problem.

But what of (b)? Is the proposition that every subroutine call would cause the address of the next instruction after the call to be stored somewhere which is a (injective) function of the memory address of the call? If so, where does the problem arise with recursion? I think maybe I'm not getting my arms around even what we're talking about when we say "memory location associated with the call".

\$\endgroup\$
8
  • 3
    \$\begingroup\$ I’m voting to close this question because this is a general programming question, not electrical engineering. It probably belongs on StackOverflow. \$\endgroup\$
    – DoxyLover
    Commented Feb 17 at 4:08
  • \$\begingroup\$ Ah, my bad. I thought maybe architecture/ISA-level questions were OK but if not I will move it over? @DoxyLover Just to be clear, this is not a question about assembly programming but about architecture decisions around how subroutines ought to return. \$\endgroup\$
    – EE18
    Commented Feb 17 at 4:11
  • 2
    \$\begingroup\$ Please add the source of the text you quoted. \$\endgroup\$
    – internet
    Commented Feb 17 at 5:00
  • 1
    \$\begingroup\$ Done, my bad! @internet \$\endgroup\$
    – EE18
    Commented Feb 17 at 5:10
  • \$\begingroup\$ @periblepsis says. Recursion eats its own tail from the same location and then unwinds. On every loop it needs a new store location.Which is what a stack does. \$\endgroup\$
    – Russell McMahon
    Commented Feb 17 at 6:27

1 Answer 1

1
\$\begingroup\$

This one is easy. It says "(b) In a memory location associated with the call, so that a different location is used when the subroutine is called from different places".

In the case of recursion, successive calls may come from the same place.

added

No one said that the machine architecture for case (b) makes a lot of sense or is an easy one to construct and make functional.

But suppose there exists a special 8-bit return address key register called X0 that the return instruction uses and suppose a call instruction performs the following steps:

  1. TEMP = HASH8(subroutine address, call instruction address)

    Here, HASH8 is some hardware block that generates an 8-bit hash code from the 16-bit subroutine address and the 16-bit target address of the call instruction.

    It is assumed to be unlikely that the same HASH8 generates unwanted collisions (given whatever justification someone comes up with.)

    However, the same call located at the same instruction address making a call to the same subroutine will produce the same HASH8.

  2. R[TEMP]= 16-bit return address from call

    R[] is a 16-bit wide data memory with an 8-bit address.

  3. X[TEMP]= X0

    X[] is an 8-bit wide data memory with an 8-bit address.

  4. X0 = TEMP

  5. PC = 16-bit address of called subroutine

Suppose the return instruction performs:

  1. TEMP = X0

  2. X0 = X[TEMP]

  3. PC = R[TEMP]

Don't ask me why anyone would do it this way. I just made it up. But it does match case (b) in your example.

Hopefully, now you can see the problem with recursion in a situation posed by case (b).

By the way, the HP21xx series of CPUs would literally blow away the first address of any called subroutine with the return address of the caller. (No stacks here!) A subroutine would look something like this:

FDATE   NOP             This location gets overwritten with return address of caller.
        LDA FILE#       Subroutine always starts here.
        SSA,RSS
        .
        .
        .
        JMP FDATE,I     Return from call.

All calls blow away the first address with the return address and then always start the subroutine at addr+1.

Now, that certainly doesn't support recursion!

\$\endgroup\$
16
  • \$\begingroup\$ Agreed, and if they do come from the same place then won't things work out fine? Suppose main() calls some function recurse() which in turn calls recurse() from line \$n\$ of the subroutine, and that in turn calls recurse() from line \$n\$ of the subroutine, and that is it for the recursion. So the deepest recurse() returns and it knows (I guess? I don't know how one would arrange this?) where to look for the memory address which is holding the address of line \$n+1\$ of recurse. Now the second deepest recurse() also returns and it uses the aforementioned, same address. So yes,... \$\endgroup\$
    – EE18
    Commented Feb 17 at 4:05
  • \$\begingroup\$ ...even though it got clobbered, it got clobbered with the same value, didn't it? \$\endgroup\$
    – EE18
    Commented Feb 17 at 4:05
  • 1
    \$\begingroup\$ There also seems to me to be a problem with what it even means to have a "memory location associated with the call". How would a returning subroutine know in general where to look? With our usual solution with a link register there is no problem -- everyone looks in the same place, namely the link register. I'm guessing the answer to this latter question will explain why recursion from the same place won't work. I have a vague sense that it's the crux of my misunderstanding. \$\endgroup\$
    – EE18
    Commented Feb 17 at 4:06
  • \$\begingroup\$ @EE18 Don't you see why the same location is a problem??? \$\endgroup\$ Commented Feb 17 at 4:16
  • \$\begingroup\$ I do not, no, at least to the extent that the returning function knows what called it (but again not sure how it would actually know that). If you're able to supply an example showing the problem when you get the chance I would greatly appreciate it. \$\endgroup\$
    – EE18
    Commented Feb 17 at 4:21

Not the answer you're looking for? Browse other questions tagged or ask your own question.