As far as I know, when a process allocates local variables, it does so by pushing them onto memory as a stack, but still accesses them as random memory by using an offset from the stack pointer to reference them (from this thread What is the idea behind using a stack for local variables?).
However, how does it know which variables have what offset? Am I thinking about this in the right way?
Local variables are stored in memory area of the corresponding function. Scope of a variable is a program part, in which a variable can be referred to. Variables declared inside a block (at the internal level), have the block as their scope.
For the main part it's the C compiler that keeps track. During the compilation process the compiler builds up a large data structure called the parse tree. It also keeps track of all variables, functions, types, ... everything with a name (i.e. identifier); this is called the symbol table.
The compiler decides where to place the six variable within this stack frame, maybe at 8 bytes from the frame start and remembers that relative position. So, the instructions that the compiler produces for the function, are: advance the stack pointer by enough bytes for all the local variables of the function.
Local variables (including parameters) are stored in the activation record of the method in which they are declared. They are accessed at runtime using an offset from the frame pointer (FP). Since we're assuming that "up" in the stack means a lower address, these offsets will be negative numbers.
Offsets of local variables are "baked into" the machine code as constants. By the time the compiler is done, things that your program referred to as local variables are replaced with fixed memory offsets assigned by compiler.
Let's say you declare three local variables:
char a[8];
int b;
short c;
The compiler assigns offsets to these variables: a
is at offset 0
, b
is at offset 8
, and c
is at offset 12
. Let's say your code does b += c
. Compiler translates this into a block of code that looks like this:
LOAD @(SP+8)
ADD @(SP+12)
STORE @(SP+8)
The only value that changes here is SP
(stack pointer). All offsets are numeric constants.
Preface: The following text uses the x86 architecture as example. Other architectures do handle things differently.
[...] it does so by pushing them into memory as a stack, [...]
That's close. it does so by pushing them into memory ON THE stack [of the current process]. Every process has its own stack. Therefore with every context switch this Stack Frame does change - and so do its local variables (on the stack).
Usually(!) locally defined variables are referenced relative to the Stack Frame saved and present in the EBP
register. This happens in contrast to globally defined varables which are referenced relative to the Data Segment Base. So every process does have its own stack with its own local variables.
Newer compilers can spare the register EBP
and reference the variables relative to the ESP
register. This has two consequences:
EBP
value as reference for the current Stack Frame to identify local variables). So this makes debugging harder without a separate debugging information file.So to answer your main question
How does a process keep track of its local variables
Processes keep track of their Stack Frame (which contains the Local Variables), but not of their Local Variables themselves. And the Stack Frame changes with each Process Switch. The Local Variables are merely referenced relative to the Stack Frame Pointer kept in the register EBP
(or relative to the Stack Pointer ESP
, which depends on the compiler settings).
Compiler does the job in memorizing the offsets. These offsets are simply hardcoded. Like to load the variable to register (eg. to eax) compiler would produce something like mov eax, [esp-4]
, where esp is stack pointer register and 4 is the offset. If new variable will be pushed next mov to get/set variable will have bigger offset. All this is compilation time analysis.
Also, the stack on some platform may be reversed - so offset will be positive.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With