-3
#include <stdio.h>

int main()
{
    size_t a = 2;
    size_t *p = &a;
    printf("%p\n", p);
}

The above code will print the memory address of a. I understand that within an OS, this address is referring to a virtual address and not the actual memory.

However, compiling a similar code (osdev.org) and running it as an actual kernel will output numbers on the screen. Where are these numbers/addresses coming from? are memory addresses hard coded in them when being manufactured?

  • When you rent a storage locker, how does the landlord assign one to you? Same basic principles. – whatsisname Sep 16 '18 at 0:46
  • Your a is on the stack; it has little to do with where your program lives. You might want to read about the stack and c calling conventions before trying to understand who assigned the stackspace to your program and how. – tkausl Sep 16 '18 at 5:40
  • The compiler hard codes them in your program. – immibis Sep 18 '18 at 4:37
3

The addresses aren’t, but their offset is when the program is compiled. When the program is loaded into memory by the OS, the start of the program is known (because that is where the OS loads it). Add in the offset, and the pointer is known.

In this program, the variable being a local variable to the function complicates matters a little. The same sort of offset concept applies to functions, though they are loaded as needed as the program runs. But they too are loaded wholesale into memory with each variable generally given its own offset from the start of the function’s stack space.

But given this is main and the size of the program, stack space might not be allocated at runtime.

The concept is the same though. The OS gives you a start address and your variables are some offset in a memory block.

  • But the question of how this is done on the OS level remains. If the above code is the actual kernel, where is the address coming from? – Josh l Sep 16 '18 at 4:02
  • @Joshl: you have a range of memory available. You need to assign some to a program. So you see what's not being used, pick some, and assign it. Pretty much the same way a hotel assigns an empty room. – whatsisname Sep 16 '18 at 4:47
  • no but this assigning is happening without me doing anything. I simply create a new int and output its address on the screen, this is a ver minimalistic kernel I created. Question is where is that address coming from? – Josh l Sep 16 '18 at 4:53
  • @Joshl - Where ever your memory manager says it comes from. – Telastyn Sep 16 '18 at 11:07
  • 2
    @Joshl "no but this assigning is happening without me doing anything." If you were handwriting assembly you would have to do something. The whole point of using higher level languages like C is that the compiler or the interpreter and associated run time libraries take care of most of the low-level book-keeping in chores like memory allocation. It can be very educational to take a look at the assembly code generated by your compiler (and to learn enough assembler to understand it). – Charles E. Grant Sep 17 '18 at 0:18
2

You're asking about how local variables obtain their addresses.

Local variables are placed onto a runtime stack.  This is done dynamically: as each function is called, it is activated by creating a fresh, new copy of its stack frame; this copy is effectively pushed onto the stack, so its location has to do with both the location of the stack, and, what else (other functions) were on the stack at the time — i.e. the dynamic call chain.

The stack frame for a function is an object whose layout is setup by the compiler or assembly language programmer, somewhat similar to other objects like structs or classes (that are local variables or go in the heap).  Variables like a in the function are like fields in this stack frame object.

Note that this dynamic stack mechanism naturally supports recursion: one function can be activated multiple times, meaning that a local variable could occur in multiple locations in the stack in the case of recursion.  This should emphasize the dynamic nature of the stack frame activation record.

The location of the runtime stack itself is determined by the operating system; it is allocated as an object in the address space of the process.

In any case, these are all just data structures; some are like classes (i.e. metadata describing data, fields, and their offsets; and others are like instances): the stack is a data structure in the process; the stack frame is a description of an activation record; the activation record is a data structure within the stack.  A variable (like a) is a field in the activation record.

As you can see, one data structure can exist within another (stack within a process, stack frame within a stack).  Addresses of individual fields and variables are created via the outer data structure's location, and the field or inner data structure's offsets within that data structure, and so on, recursively.

The same is true whether the thread is a kernel thread or user thread.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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