Structure / Separate Stack Frame page ?

edit

The "Structure" section is pretty good and comprehensive, it might make sense to consider putting the "stack frame"-related stuff on a separate "Stack Frame" page, what do you guys think?

Here are some additional pointers to help improve the "Stack Frame" related article:

Functions of the call stack section

edit
...One is that each task can have its own stack, and thus the subroutine can be reentrant, that is, can be active simultaneously for different tasks doing different things...

I don't really see the connection between each task having its own stack and reentrancy being possible. Reentrancy would be possible even in the case of a stack that is shared between multiple tasks (each task pushes its own stack frame onto the stack and voila one has reentrancy). Could be better written as

...One advantage of stacks is that they allow sub routines to be reentrant...

Another issue I saw is with this line:

...Another benefit is that recursion is automatically supported...

Again, recursion is merely a special case of re-entrance, so isn't this line a bit redundant?

Proposed merge with Stack-based memory allocation

edit

Merge to main Call stack#Local data storage . Prev proposal Talk:Call_stack/Archive_1#Merger_proposal. Some parts may be merged to Stack (abstract data type). Widefox; talk 16:04, 8 October 2017 (UTC)Reply

  • The previous discussion has three votes for not merging. (One agrees that it should not merge, confusing if you don't read carefully.) They are different things. Note, for one, that stack-based memory allocation does not require a stack. Some systems implement it using a linked list, though the logic is stack-like. More generally, as noted in the name, stack is an abstract data type. A call stack is one not so abstract implementation, and as noted above doesn't even need a physical stack. Gah4 (talk) 04:24, 9 October 2017 (UTC)Reply
Closing, given the consensus not to merge. Klbrain (talk) 10:28, 6 January 2019 (UTC)Reply
  Resolved

This needs to discuss calls that *don't* immediately push the return address onto the call stack

edit

These days, most instruction sets used in general-purpose computing (including most if not all RISCs, as well as the CISC S/390+z/Architecture) have a call instruction that puts the return address into a register, leaving it up to the *called* routine to push that register onto the call stack *if* it will be using that register for other purposes such as a subsequent call; x86 may be one of the few remaining ISAs that do the push in the calling instruction.

We should discuss that. Guy Harris (talk) 17:50, 20 May 2019 (UTC)Reply

Well, for one, it doesn't well describe the predecessors to ESA/390 and z, which don't have any stack instructions. IBM S/360 and S/370 Fortran compilers commonly store the return address as static data, since recursion didn't come until Fortran 90. The calling convention uses a doubly linked list instead of a physical stack, though logically it is related to a stack. Reentrant routines (either recursive or for multitasking) need to dynamically allocate a register save area, unless they are leaf routines. Note also that argument passing does not necessarily use the same stack as return addresses. (Some places should probably say a stack instead of the stack.) Gah4 (talk) 20:02, 20 May 2019 (UTC)Reply
You don't need stack instructions to implement a call stack.
The calling sequences for IBM's OSes may be different from the simple stack-based calling sequences used on DEC's PDP-11 operating systems and their successors, as well as on UN*X and Windows, so they might deserve a separate discussion.
UN*Xes on System/370 and successors, however, use a stack-based calling sequence, in which, as far as I know, the prologue either always pushes the GPR used as the return address onto the stack or does so except in leaf procedures, and no stack-oriented instructions are needed or used - i.e., they work the same way as they do on other ISAs with "save the return address to a register" procedure call instructions. See, for example, the 32-bit S/3x0 ABI and the 64-bit z/Architecture ABI.
So it's not a question of "the predecessors to ESA/390 and z, which don't have any stack instructions", it's a question of "the operating systems that IBM shipped with the predecessors to ESA/390 and z" - and did those calling sequences change with OS/390? Guy Harris (talk) 20:53, 20 May 2019 (UTC)Reply
Things have changed a little over the years, but not so fundamentally. XA/370 adds 31 bit addressing, but 24 bit addressing doesn't go away. It is necessary to be able to call routines that do 24 bit addressing, but also that put other data in the high bits. z/OS will load and run a load module from OS/360. Some things have been more standardized, to make inter-language calls work better. There is LE (Langauge Environment) and CEE (I thought was named after the C languages, but turns out to be Common Execution Environment). Efficient calling requires a fast way to allocate/deallocate save areas. z/OS extends data addressing to 64 bits, but code addressing, as well as I know, is still 31 bits. Save areas have to store the 64 bit registers, though. For some reason, many years ago I signed up for the Linux/390 mailing list, but pretty much never read what it sends me. Standard CALL linkage Conventions has some of the discriptions on how things work. Gah4 (talk) 01:58, 21 May 2019 (UTC)Reply

This page is written currently written under the assumption that a simple stack discipline, in which, for example, a call is done by pushing arguments onto the stack, pushing the return address onto the stack, and then jumping to the called routine, is used.

At least for Unix/Unix-like systems, and Windows, the only current platform that works that way is 32-bit x86. Even in 64-bit x86, whilst the call operation pushes the return address onto the stack, the first few arguments are passed in registers. In most other instruction sets, even the return address is put into a register by the call operation, and it's the callee's job to save that register if necessary; the stack frame for a leaf routine won't contain the return address - that will be in a register, unless that register is a general-purpose register that's used for other purposes in the routine.

Updating the page to include non-simple stack disciplines such as those will require some additional work. Guy Harris (talk) 07:17, 28 August 2022 (UTC)Reply

I haven't checked this so recently, but the ones I remember still leave space on the stack, even when the values are in registers. The called routine can then write them to the stack. In that sense, then, keeping them in registers is an optimization only. Logically, it is not different. Similarly, the doubly linked list used by IBM since OS/360 is logically a stack, but not physically. The article, will then, have to make the distinction between physical and logical stack. Gah4 (talk) 10:33, 28 August 2022 (UTC)Reply
"but the ones I remember still leave space on the stack, even when the values are in registers" Presumably they only do so if there's a requirement to write the registers to the stack, e.g. if either 1) there are caller-save registers with live values or 2) there's a need to spill a register to free it up for an operation. In a calling sequence in which the return address is put into a register, the return address register is caller-save, so a leaf routine, as it's never a calling routine, never needs to save it, so the compiler has no need to leave space on the stack for it, and shouldn't do so. The same applies to parameters passed in registers.
"The article, will then, have to make the distinction between physical and logical stack." Or just note that, while it's logically a stack - which is the most important aspect - it isn't implemented physically as a single contiguous stack region, as it is on UN*Xes, Windows, OpenVMS, etc.. Guy Harris (talk) 19:27, 28 August 2022 (UTC)Reply
It was some years ago, that I was reading about Sun/SPARC calling conventions. The first words stay in registers. If a double precision value goes on the stack, half might be in a register and half on the stack. Programs would usually store the register so the whole value was on the stack. It is callee save, but the caller makes the stack frame. SPARC has register windows, with input and output registers, specifically so arguments in registers work. There is a different set in the called routine, unless the register stack is full. Gah4 (talk) 21:19, 28 August 2022 (UTC)Reply