In case of push during function call, why the stack pointer moves to a
smaller value by subtracting 4 times the number of registers to be
pushed on the stack?
I got this while reading Understanding the stack
In the same page, it is clearly mentioned about the memory layout of stack :-
It's useful to think of the following aspects of a stack.
stack bottom The largest valid address of a stack. When a stack is initialized, the stack pointer points to the stack bottom.
stack limit The smallest valid address of a stack. If the stack pointer gets smaller than this, then there's a stack overflow (this
should not be confused with overflow from math operations).
Other sections of memory are used for the program and for the heap
(the section of memory used for dynamic memory allocation).
And, talking about the PUSH operation, subtracting 4 times the number of registers to be pushed on the stack is needed because in MIPS architecture, addresses of sequential words differ by 4. And, the registers are 32 bits(4 bytes) for MIPS I instruction set architecture (ISA) and II ISA.
For our stack of 4-byte (full word) data, adding an item means subtracting four from $sp and storing the item in that address.
Here is what that looks like in code. Say that the value to push on the stack is in register $t0:
# PUSH the item in $t0:
subu $sp,$sp,4 # point to the place for the new item,
sw $t0,($sp) # store the contents of $t0 as the new top.
And, so, you can push one or more registers, by setting the stack pointer to a smaller value (usually by subtracting 4 times the number of registers to be pushed on the stack) and copying the registers to the stack.
Related
I know that a stack can be implemented by dynamic array (e.g. std::vector in c++) or linked list.
When the stack is implemented based on dynamic array, the capacity will grow automatically the new item is push into the stack. I'm wondering that when pop out items from stack, will the capacity of the array decrease?
In some applications (e.g path search algorithms), many items will be pushed into the stack first and then pop out. The program ends when the stack is empty. If the capacity of the array didn't decrease, I will have a large empty array when my program ends.
std::stack uses std::deque as container. It's resized as required, both up and down.
When the hardware pushes a segment register on the stack to save a far pointer because the calling procedure called a procedure in another segment, apparently, it does not save the invisible part of the segment register (the cached segment descriptor part) and only saves the selector part.
That, of course, is fine as that gives you really all you need to know to access the descriptor.
But, the selector is only 16 bits and if your addressing default size is 32 or 64, the hardware on its own invisible to the process will push the segment selector on the stack and increment the stack pointer 4 or 8 bytes despite the fact that the selector only requires 2.
This is to keep the stack pointer aligned which is important.
My question is: what does the hardware use to fill in the extra bytes?
Does it sign extend the selector?
Does it 0 extend the selector?
Does it just push the two selector bytes and then jump the stack pointer an extra 2 or 6 leaving whatever was there initially alone?
Thanks.
According to the entry for the PUSH instruction in the Intel 64 and IA-32 Architectures Software Developer’s Manual, Volume 2 (link)
If the source operand is a segment register (16 bits) and
the operand size is 64-bits, a zero-extended value is pushed on
the stack; if the operand size is 32-bits, either a zero-extended
value is pushed on the stack or the segment selector is written on the
stack using a 16-bit move. For the last case, all recent Core and Atom
processors perform a 16-bit move, leaving the upper portion of the
stack location unmodified.
So it seems to either 0 extend or leave what was there unmodified depending on the operand size.
-module(demo).
-export([factorial/1]).
factorial(0) -> 1;
factorial(N) ->
N * factorial(N-1).
The factorial is not tail recursive but why is it not overflowing the stack? I am able to get factorial of 100,000 without stack overflow but takes some time to compute.
An Erlang process's "stack" is not stored in the stack given by the system to the process (which is usually a few megabytes) but in the heap. As far as I know, it will grow unbounded until the system refuses to give the VM more memory.
The size includes 233 words for the heap area (which includes the stack). The garbage collector increases the heap as needed.
The main (outer) loop for a process must be tail-recursive. Otherwise, the stack grows until the process terminates.
Source
If you monitor the Erlang VM process in an process monitor like Activity Monitor on OSX or top on other UNIX-like systems, you'll see that the memory usage will keep on increasing until the calculation is complete, at which point a part of the memory (the one where the "stack" is stored) will be released (this happens gradually over a few seconds after the function returns for me).
Or the Interrupt Stack is a special stack cointained in Kernel Stack?
I'm a little bit confused because sometimes my book refers at it with only "stack".
It depends on kernel configuration (CONFIG_4KSTACKS)
Case 1: When CONFIG_4KSTACKS is not set
In this case, kernel stack size per thread is 8K( 2 pages) and ISR will use same kernel stack.
Case 2: When CONFIG_4KSTACKS is set.
In this case, kernel stack size per thread is 4K( 1 page) and ISR will have separate stack of 4k(1 page)
Check http://www.makelinux.net/books/lkd2/ch06lev1sec5 for more updates.
I am exploring the lower level workings of the system, and was wondering how malloc determines the start address of the heap. Is the heap at a constant offset or is there a call of some sort to get the start address? Does the stack affect the start address of the heap?
sbrk returns the start address of the bytes it adds (or removes). In a fresh process with no heap allocated yet, the first call to sbrk should then return the start address of the "break" section of the heap. If I had to bet, that's what malloc implementations which use brk/sbrk probably do on their first run.
Traditionally, the heap started just above the text section and grew up; stack frames didn't affect start address at all as they grow down towards the unmapped 0 page. However, it's more common these days for
The first address to be randomized, to make it harder for exploits to hit the right address in memory
The heap to be non-contiguous, as malloc() usually just calls mmap() to get an address anywhere in the virtual address space