Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to insist a C compiler put local variables on the stack, not in registers

I am trying to port an historical functional language interpreter (KRC for EMAS) to modern systems (C for Unix) and it has a garbage collector that expects to be able to scan the stack for pointers into the heap to know which pointers it must relocate when objects in the heap are moved during a GC. For this to work, all function arguments and local variables that point into the heap must be found in the stack.

Now, there was a time when the "register" keyword meant "you can put this variable in a register if you like" and otherwise it was on the stack, but nowadays all (GCC, Clang, Tinyc/tcc) C compilers seem to put local variables into registers regardless, with no way to disable this behaviour and the result is that that the GC is missing out on some values belonging to in-progress functions, failing to preserve them and corrupting the heap.

Is there a way to tell any of these compilers to use the original C semantics, whereby all local variables are on the stack unless you say "register"?

I have a few warty "solutions":

  • adding extra code everywhere to take the address of each heap-oriented local variable and passing it to a dummy function, as a way of forcing it to be in a memory location;
  • making all static functions global so as to avoid function inlining and the resultant optimising-out of the inlined function's parameters;
  • bracketing the GC() function with a stub that pushes all the machine registers onto the stack, calls the real GC() function and then pops them;

which all seem to improve matters, but are awfully hacky and unreliable.

Is there a better way to achieve the required result, of ensuring that all function parameters and local variables will be on the stack?

like image 962
martinwguy Avatar asked Mar 08 '15 10:03

martinwguy


People also ask

Do local variables go on the stack?

The stack is used for dynamic memory allocation, and local variables are stored at the top of the stack in a stack frame. A frame pointer is used to refer to local variables in the stack frame.

Why local variables are allocated on the stack in C?

Advantages of using Stack When a function is called the local variables are stored in a stack, and it is automatically destroyed once returned. A stack is used when a variable is not used outside that function. It allows you to control how memory is allocated and deallocated. Stack automatically cleans up the object.

Are local variables stored in registers?

Local variables are stored in registers in most cases, because registers are pushed and poped from stack when you make function calls It looks like they are on stack.

Where are variables stored on the stack?

The stack is memory like everything else and what is pushed on the stack is a reserved area of a specific size, the variables just live inside this space but they are just memory accesses as any other, the whole memory area is removed when the method returns. Think of the stack as a stack of papers.


2 Answers

I suppose that you use a kind of "mark and sweep" GC. In such case you only need to save registers at the moment when marking phase starts. My advise is to examine your GC, find the place where the "mark and sweep" operation starts and to put a code placing all registers into an accessible memory here. setjmp is a semi-portable way to achieve this (unless you are working on sparc).

like image 58
Marian Avatar answered Oct 10 '22 04:10

Marian


Ok, that is an odd GC; well, you might have use for the volatile keyword.

It was originally meant for things like memory-mapped devices, where you'd want to force your compiler not to optimize away a variable. It's use and abuse has been a long standing topic of discussion.

Is there a better way to achieve the required result

Really really hard to answer. On one hand: obviously, yes: don't let your GC rely on things that can't be relied upon. But that means rewriting it. On the other hand: if things like additional code to ensure stack placement work, then why the hell not go for it? It's not like you're code-porting a historical interpreter for performance.

like image 22
Marcus Müller Avatar answered Oct 10 '22 03:10

Marcus Müller