void function(int a, int b, int c) {
char buffer1[5];
char buffer2[10];
}
We must remember that memory can only
be addressed in multiples of the word
size. A word in our case is 4 bytes,
or 32 bits. So our 5 byte buffer is
really going to take 8 bytes (2 words)
of memory, and our 10 byte buffer is
going to take 12 bytes (3 words) of
memory. That is why SP is being
subtracted by 20.
Why it's not ceil((5+10)/4)*4=16?
Because individual variables should be aligned. With your proposed formula, you'd align only the first variable on the stack, leaving following variables unaligned, which is bad for performance.
This is also known as "packing" and can be done in C/C++ with pragmas, but is only useful in very specific cases and can be dangerous both for performance and as a cause of potential runtime traps. Some processors will generate faults on unaligned accesses at runtime, which will crash your program.
The variables on your architecture are aligned individually. buffer1 gets rounded up to 8 and buffer2 to 12 so that both of their starting addresses are 4-byte aligned. So 8+12 = 20.
Related
How do data types get allocated in stack in MIPS architecture?
If i have 2 char and 1 int data, is stack going to allocate them in 8 byte form(2 chars are in same memory segment and 1 int is in another memory segment) or 12 byte form(memory segment for each chars and 1 memory segment for int)? I am trying to understand 32 bit MIPS architecture.
To the question, it matters if the data types being allocated are for local variables vs. for parameter passing.
For locals you can allocate whatever you want as long as the int is aligned on 4 byte boundary. The total stack allocation is rounded up to 8 bytes (though some don't bother with this, e.g. for homework, and, is only strictly necessary if your function calls other functions that may rely on the expected 8 byte alignment of the stack.)
For parameters you should follow the documented calling convention — there are several so you have to know which you're working with. See here to see some of them; look for "MIPS EABI 32-bit Calling Convention" and/vs. "MIPS O32 32-bit Calling Convention".
What they have in common is that the first four parameters are passed in registers, which effectively means that chars take a full 32-bit word; char parameters passed on the stack also follow that form, so take a full 32-bit word each.
I understand that physical memory is accessed by aligned chunks of 4(32-bit) or 8(64-bit) bytes.
But why do we need aligned data for memory address, lets say(in 32 bit machine):
I have a char c start at address 0(char takes one byte, then I have an integer i which start at address 1, so when I want to access the i, computer get the address of i which is 1, and then read 4 bytes from address 1 directly.
So if it works in this way, why do we need to pad 3 bytes after char c?
As you said, "memory can be accessed by aligned chunks of 4 or 8 bytes" depending on the architecture of a computer. This means the processor does access memory only on chunks of addresses dividable by 4 or 8 (this has pretty much to do with cost and design complexity I guess).
Let's illustrate your example :
struct foo {
char c;
int i;
};
Say foo is aligned in memory at address 0x100. If you access foo.c, you are accessing one byte only, but behind the scenes an entire word of 4 bytes has been read from memory by the CPU and the 3 next bytes in the word have been discarded.
Now if you read foo.i (wich is 4 bytes long) at memory location 0x101, the CPU will need two memory transactions. One at address 0x100 where it gets the three first bytes, and then the other one at address 0x104 to fetch the last remaining byte.
In the end, aligned data in memory saves unnecessary memory transactions.
If something is stored at 0x1001 0000 the next thing is stored at 0x1001 0004. And if I'm correct the memory pieces in a 32-bit architecture are 32 bits each. So would 0x1001 0002 point to the second half of the 32 bits?
First of all, memory addresses in MIPS architecture are not incremented by 4. MIPS uses byte addressing, so you can address any byte from memory (see e.g. lb and lbu to read a single byte, lh and lhu to read a half-word).
The fact is that if you read words which are 32 bits length (4 bytes, lw), then two consecutive words will be 4 bytes away from each other. In this case, you would add 4 to the address of the first word to get the address of the next word.
Beside this, if you read words you have to align them in multiples of 4, otherwise you will get an alignment exception.
In your example, if the first word is stored in 0x10010000 then the next word will be in 0x10010004 and of course the first half/second half would be in 0x1001000 and 0x1001002 (the ordering will depend on the endianness of the architecture).
You seem to have answered this one yourself! 32 bits make 4 bytes, so if you're e.g. pushing to a stack, where all elements are pushed as the same size, each next item will be 4 bytes ahead (or before) the next.
Why is the smallest value that can be stored a Byte(8bit) & not a Bit(1bit) in memory?
Even booleans are stored as Bytes. Will we ever bump the smallest number to 32 or 64bits like register's on the CPU?
EDIT: To clarify as many answers seemed confused about the nature of questing. This question is about why isn't a byte 7-bit, 1-bit, 32-bit, etc (not why lower bit primitives must fit within the hardware's byte at min). Is the 8-bit byte simply historical as some hardware has 10-bit bytes for example. Or is there a mathematical reason 8-bit is ideal vs say 10-bit for general processing?
The hardware is built to read data in blocks (bytes, later words and dwords). This provides greater efficiency, than accessing individual bits, and also offers more addressing range. So most data is aligned to at least byte boundary. There exist encodings that operate with bit sequences, rather than bytes, but they are quite rare.
Nowadays the data is most often aligned to dword (32-bits) boundary anyway. Moreover, some hardware (ARM, for example), can't access misaligned multibyte variables, i.e. 16-bit word can't "cross" dword boundary - exception will be thrown.
Because computers address memory at the byte level, so anything smaller than a byte is not addressable.
The underlying methods of processor access are limited to the size of the smallest usable register. On most architectures, that size is 8 bits. You can use smaller portions of these; for instance, C has the bitfield feature in structs that will allow combining fields that only need to be certain bit lengths. Access will still require that the whole byte be read.
Some older exotic architectures actually did have different a "word size." In these machines, 10 bits might be the common size.
Lastly, processors are almost always backwards compatible. Intel, for instance, has maintained complete instruction compatibility from the 386 on up. If you take a program compiled for the 386, it will still run on an i7 processor. Changing the word size would break compatibility. So while it is possible, no manufacturer will ever do it.
Assume that we have native language that consist of 2 character such as a , b
to distinguish two characters we need at least 1 bit for example 0 to represent char a and 1 to represent char b
so that if we count number of characters and special characters and symbols, there are 128 character and to distinguish one character from another, you need log2(128) = 7 bit and 8th bit for transmission
Is it possible to create an array that doesn't cross 256 byte boundary? That is addresses of the individual array items only differ in the lower byte. This is weaker requirement than keeping the array aligned to 256 bytes. The only solution I could think of was aligning to next_power_of_two(sizeof(array)), but I'm not sure about the gaps that would appear this way.
It is for a library for AVR microcontrollers, and this would save me a few precious instructions in an interrupt handler.The array that should have this property is 54 byte long out of about 80 bytes of total static memory used by the library. I'm looking for a way that doesn't increase the memory requirements.
I'm using avr-as gnu assembler and avr-ld linker.
Example:If the array starts at address 0x00f0, then the higher word will change from 0x00 to 0x01 while traversing the array.
I don't really care whether it starts at address 0x0100 or 0x0101 as long as it doesn't cross the boundary.
You only need 64 byte alignment to meet this requirement, so e.g. this should work:
uint8_t a[54] __attribute__ ((aligned(64)));
I don't know anything about AVR microcontrollers, but, generally speaking, static variables are usually placed in the data section of the executable, and, since your static memory requirements are low, all you need to ensure is that the data section is 256 byte aligned. (Which it may be by default. On x86, it usually is.) Check the linker options...