Understanding what happens under the hood

Started by
13 comments, last by Sir_Spritely 20 years, 1 month ago
Like someone said you are opening up a can o worms.
Anyways on windows this is all the work the OS does just to get your compiled exe running(from inside windows book):
A Win32 process is created when an application calls one of the process creation functions, such as CreateProcess, CreateProcessAsUser, or CreateProcessWithLogonW. Creating a Win32 process consists of several stages carried out in three parts of the operating system: the Win32 client-side library Kernel32.dll, the Windows 2000 executive, and the Win32 subsystem process (Csrss). Because of the multiple environment subsystem architecture of Windows 2000, creating a Windows 2000 executive process object (which other subsystems can use) is separated from the work involved in creating a Win32 process. So, although the following description of the flow of the Win32 CreateProcess function is complicated, keep in mind that part of the work is specific to the semantics added by the Win32 subsystem as opposed to the core work needed to create a Windows 2000 executive process object.

The following list summarizes the main stages of creating a process with the Win32 CreateProcess function. The operations performed in each stage are described in detail in the subsequent sections.


1.Open the image file (.exe) to be executed inside the process.


2.Create the Windows 2000 executive process object.


3.Create the initial thread (stack, context, and Windows 2000 executive thread object).


4.Notify the Win32 subsystem of the new process so that it can set up for the new process and thread.


5.Start execution of the initial thread (unless the CREATE_SUSPENDED flag was specified).


6.In the context of the new process and thread, complete the initialization of the address space (such as load required DLLs) and begin execution of the program

and I got this from memory mangagment book
Memory Allocation
When the kernel allocates physical memory for a process, it sets up the allocated memory so that the first address (i.e., the lowest address) is a multiple of 64KB. In other words, processes are aligned in physical memory on a 64KB boundary. The size of the address space reserved for a process is a multiple of the native processor''s page size. On a Pentium, an application would be given a plot of real estate in physical memory that is a multiple of 4KB. The Pentium does provide facilities for larger page sizes (i.e., 4MB), but everyone in their right mind sticks to 4KB page sizes (MMURTL, Linux, Windows, etc.).

One of the fringe benefits of being a user process is that each task is constructed with its own heap. Figure 2.22 displays one of the possible memory layouts for a user process. The stack grows down from the highest address, and the heap grows up toward the stack.
The exact organization of a program''s code, data, stack, and heap sections are a function of the development tools used to build the program. Linkers, in particular, can decide where to place an application''s components. The linker will normally process object files in the order in which they appear on its command line. For each object file, the linker will embed program sections into the executable as it encounters them. The /DO linker option can be used to alter this behavior so the program''s sections are arranged in the Microsoft Default Order.




If God played dice, He''d win.
—Ian Stewart, Does God Play Dice? The Mathematics of Chaos
If God played dice, He'd win.—Ian Stewart, Does God Play Dice? The Mathematics of Chaos
Advertisement
I think your getting a little confused between compile and runtime and the stack and the heap.

The stack consists of data that is not explicitly dynamically allocated using new or malloc. However, this does not mean that it can be created at compile-time. For example consider the function below.

int factorial(int operand){  if (operand == 1)  {    return 1;  }  return operand * factorial(operand-1);}



Say you ask a user to input an integer num and then call factorial(num). There is no way for the compiler to know how many times factorial(int) will be run...

and each call to num results in the addition of an element (the activation record - which includes the local variables initialized, the return addy, etc.) in the call stack. So the stack too is created at runtime.

The difference essentially is that when you initialize a variable in a function - at the end of the function the variable loses its scope and is automatically detroyed.

However, when you allocate memory on the heap explicitly, the new memory is allocated off the call stack, in a separate structure called the heap. When you leave the function scope, the stack is cleaned, but the memory allocated is not. So....

   struct useless_struct{int *value;}void assign_to_struct(int i, useless_struct &inst){  // inst.value = i; // i will be cleaned off the stack,                     //leaving a dangling ptr  inst.value = new int(i); // this works OK}


So essentially both the stack and heap are runtime components of variable size. The only fixed size is that of the code(functions definitions, struct and class sizes, and globals)....

Hope that helps...
BTW i know this is a lot to digest at once, which is why i highly recommend a book, because im sure a PhD can explain this much better than I

EDIT: Stupid me... i forgot the ampersand in the func def..

[edited by - psamty10 on March 9, 2004 2:21:52 PM]

[edited by - psamty10 on March 9, 2004 2:22:29 PM]
Thanks a lot for all the help. This is exactly what I need, it is REALLY appreciated!!
"If anyone knows any really decent resources on this I would appreciate the URL. Or if you want to have a go at explaining it, I would appreciate that also."
free online book with all the gory technical details if you can stomach it


If God played dice, He''d win.
—Ian Stewart, Does God Play Dice? The Mathematics of Chaos
If God played dice, He'd win.—Ian Stewart, Does God Play Dice? The Mathematics of Chaos
quote:Original post by psamty10
    struct useless_struct{int *value;}void assign_to_struct(int i, useless_struct &inst){  // inst.value = i; // i will be cleaned off the stack,                     //leaving a dangling ptr  inst.value = new int(i); // this works OK}


EDIT: Stupid me... i forgot the ampersand in the func def..


Thanks for the explanation. I was wondering about this myself too.

Oh, and you forgot an ampersand for inst.value = i too.




--{You fight like a dairy farmer!}

--{You fight like a dairy farmer!}

This topic is closed to new replies.

Advertisement