I can't understand how memory is allocated in the following code:
#include<stdio.h>
#include<string.h>
int main()
{
char a[]={"text"};
char b[]={'t','e','x','t'};
printf(":%s: sizeof(a)=%d, strlen(a)=%d\n",a, sizeof(a), strlen(a));
printf(":%s: sizeof(b)=%d, strlen(b)=%d\n",b, sizeof(b), strlen(b));
return 0;
}
The output is
:text: sizeof(a)=5, strlen(a)=4
:texttext: sizeof(b)=4, strlen(b)=8
By looking into memory addresses and the output code it seems that variable b is placed before variable a, and that's why strlen(b), by looking for \0, returns 8.
Why does this happen? I expected variable a to be declared first.
The language makes no guarantees about what is placed where. So, your experiment make very little sense. It might work, it might not. The behavior is undefined. Your b is not a string and it is UB to use strlen with something that is not a string.
From the purely practical point of view though, local variables are usually allocated on the stack, and the stack on may moderns platforms (like x86) grows backwards, i.e. from higher addresses to lower addresses. So, if you are using one of these platforms, it is possible that your compiler decided to allocate variables in the order of their declaration (a first and b second), but because stack grows backwards b ended up at lower addresses in the memory than a. I.e. b ended up before a in memory.
One can note though that a typical implementation does not normally allocate stack space for local variables one-by-one. Instead, the entire block of memory for all local variables (stack frame) is allocated at once, meaning that the logic I described above does not necessarily apply. Yet, it is still possible that the compiler still follows the "reverse" approach to local variable layout anyway, i.e. variables declared earlier are placed later in the local memory frame, "as if" they were allocated one-by-one in the order of their declaration.
Your "b" character array is not null-terminated. To understand consider that the char a[] declaration is equivalent to:
char a[] = { 't', 'e', 'x', 't', '\0' };
In otherwords strlen(b) is undefined, it just looks through random memory for a NULL character (0 byte).
I do not get the same output see here on my ideone snippet: http://ideone.com/zHhHc
:text: sizeof(a)=5, strlen(a)=4
:text
When I use codepad, I see different output than you: http://codepad.org/MXJWY136
:text: sizeof(a)=5, strlen(a)=4
:text: sizeof(b)=4, strlen(b)=4
Also, when I compile it a C++ compiler, I get the same output: http://ideone.com/aLNjv
:text: sizeof(a)=5, strlen(a)=4
:text: sizeof(b)=4, strlen(b)=4
So something is definitely wrong on your platform and/or compiler. It could be undefined behavior (UB) due to the fact that your char array does not have a null-terminator (\0). At any rate...
While both a and b may look the same, they are not due to how you have defined the character arrays.
char a[] = "text";
What this array looks like in memory is the following:
----------------------
| t | e | x | t | \0 |
----------------------
The double quotes mean "text string" and will add the \0 automatically (that's why the size is 5). In b, you have to add it manually but the size is 4. The strlen() in b is searching until end in your implementation, which could include garbage characters. This is a big problem in many security aspects of coding for char arrays that are not null terminated.
I compiled your code on Linux/x86 with GCC using the -S flag to see assembly output. That shows that for me, b[] is allocated at a higher memory address than a[], so I didn't get strlen(b)=4.
.file "str.c"
.section .rodata
.align 4
.LC0:
.string ":%s: sizeof(a)=%d, strlen(a)=%d\n"
.align 4
.LC1:
.string ":%s: sizeof(b)=%d, strlen(b)=%d\n"
.text
.globl main
.type main, #function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $32, %esp
movl %gs:20, %eax
movl %eax, 28(%esp)
xorl %eax, %eax
movl $1954047348, 19(%esp)
movb $0, 23(%esp)
movb $116, 24(%esp)
movb $101, 25(%esp)
movb $120, 26(%esp)
movb $116, 27(%esp)
leal 19(%esp), %eax
movl %eax, (%esp)
call strlen
movl %eax, %edx
movl $.LC0, %eax
movl %edx, 12(%esp)
movl $5, 8(%esp)
leal 19(%esp), %edx
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
leal 24(%esp), %eax
movl %eax, (%esp)
call strlen
movl $.LC1, %edx
movl %eax, 12(%esp)
movl $4, 8(%esp)
leal 24(%esp), %eax
movl %eax, 4(%esp)
movl %edx, (%esp)
call printf
movl $0, %eax
movl 28(%esp), %edx
xorl %gs:20, %edx
je .L2
call __stack_chk_fail
.L2:
leave
ret
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2"
.section .note.GNU-stack,"",#progbits
In the code above, $1954047348 followed by $0 is a[] with the null termination. The 4 bytes after that are b[]. This means b[] was pushed on the stack before a[] since the stack grows down on this compiler.
If you compile with -S (or equivalent), you should see b[] at a lower address than a[], so you'll get strlen(b)=8.
Related
Suppose I have the following C code:
#include
int main()
{
int x = 11;
int y = x + 3;
printf("%d\n", x);
return 0;
}
Then I compile it into asm using gcc, I get this(with some flag removed):
main:
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
movl $11, -4(%rbp)
movl -4(%rbp), %eax
addl $3, %eax
movl %eax, -8(%rbp)
movl -4(%rbp), %eax
movl %eax, %esi
movl $.LC0, %edi
movl $0, %eax
call printf
movl $0, %eax
leave
ret
My problem is why it is movl -4(%rbp), %eax followed by movl %eax, %esi, rather than a simple movl -4(%rbp), %esi(which works well according to my experiment)?
You probably did not enable optimizations.
Without optimization the compiler will produce code like this. For one it does not allocate data to registers, but on the stack. This means that when you operate on variables they will first be transferred to a register and then operated on.
So given that x lives is allocated in -4(%rbp) and this is what the code appears as if you translate it directly without optimization. First you move 11 to the storage of x. This means:
movl $11, -4(%rbp)
done with the first statement. The next statement is to evaluate x+3 and place in the storage of y (which is -8(%rbp), this is done without regard of the previous generated code:
movl -4(%rbp), %eax
addl $3, %eax
movl %eax, -8(%rbp)
done with the second statement. By the way that is divided into two parts: evaluation of x+3 and the storage of the result. Then the compiler continues to generate code for the printf statement, again without taking earlier statements into account.
If you on the other hand would enable optimization the compiler does a number of smart and to humans obvious things. One thing is that it allows variables to be allocated to registers, or at least keep track on where one can find the value of the variable. In this case the compiler would for example know in the second statement that x is not only stored at -4(%ebp) it will also know that it is stored in $11 (yes it nows it's actual value). It can then use this to add 3 to it which means it knows the result to be 14 (but it's smarter that that - it has also seen that you didn't use that variable so it skips that statement entirely). Next statement is the printf statement and here it can use the fact that it knows x to be 11 and pass that directly to printf. By the way it also realizes that it doesn't get to use the storage of x at -4(%ebp). Finally it may know what printf does (since you included stdio.h) so can analyze the format string and do the conversion at compile time to replace the printf statement to a call that directly writes 14 to standard out.
So I do have some assembly code which I wrote on my linux VM (Manjaro, x86_64). It looks like this:
.section .rodata
.LC0:
.string "The value of a is: %d, of b: %d"
.text
.globl main
.type main, #function
main:
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
movl $15, -4(%rbp)
movl $20, -8(%rbp)
movl -8(%rbp), %edx
movl -4(%rbp), %eax
movl %eax, %esi
movl $.LC0, %edi
movl $0, %eax
call printf
movl $0, %eax
leave
ret
Basically I want to insert 2 values in registers, then somehow print them (formated like in .LC0). Well, I got stuck, so I just wrote C program, and used gcc -S to see how it looks. It gave me something similair to the code above. I don't understand two things:
If I store 20 in %edx and 15 in %eax, then why passing only %eax to %esi causes printf to print the values both from %eax and %edx?
Why do I have to put a zero constant everytime before and after printf (as gcc does?)
Why do I have to put a zero constant everytime before and after printf
These are two different issues.
Zero before printf conforms to x86-64 a.k.a. AMD64 SysV ABI to specify count of variable arguments in vector (XMMn, YMMn...) registers.
Zero after printf is this function return value (likely, return 0 at its end).
why passing only %eax to %esi causes printf to print the values both from %eax and %edx?
It does not.
The same ABI specifies: the first argument (printf format string pointer) in %rdi; the second argument (first variable argument) in %rsi, and so on. Additional move of arguments seems to be artifact of non-optimized (-O0) gcc output code. If you add any optimization (even -Og), youʼll see these senseless moves wiped out.
why is the output 44 instead of 12, &x,eip,ebp,&j should be the stack layout for the code
given below i guess, if so then it must have 12 as output, but i am getting it 44?
so help me understand the concept,altough the base pointer is relocated for every instant of execution, the relative must remain unchanged and should not it be 12?
int main() {
int x = 9;
// printf("%p is the address of x\n",&x);
fun(&x );
printf("%x is the address of x\n", (&x));
x = 3;
printf("%d x is \n",x);
return 0;
}
int fun(unsigned int *ptr) {
int j;
printf("the difference is %u\n",((unsigned int)ptr -(unsigned int) &j));
printf("the address of j is %x\n",&j);
return 0;
}
You're assuming that the compiler has packed everything (instead of putting things on specific alignment boundaries), and you're also assuming that the compiler hasn't inlined the function, or made any other optimisations or transformations.
In summary, you cannot make any assumptions about this sort of thing, or rely on any particular behaviour.
No, it should not be 12. It should not be anything. The ISO standard has very little to say about how things are arranged on the stack. An implementation has a great deal of leeway in moving things around and inserting padding for efficiency.
If you pass it through your compiler with an option to generate he assembler code (such as with gcc -S), it will become evident as to what's happening here.
fun:
pushl %ebp
movl %esp, %ebp
subl $40, %esp ;; this is quite large (see below).
movl 8(%ebp), %edx
leal -12(%ebp), %eax
movl %edx, %ecx
subl %eax, %ecx
movl %ecx, %eax
movl %eax, 4(%esp)
movl $.LC2, (%esp)
call printf
leal -12(%ebp), %eax
movl %eax, 4(%esp)
movl $.LC3, (%esp)
call printf
movl $0, %eax
leave
ret
It appears that gcc is pre-generating the next stack frame (the one going down to printf) as part of the prolog for the fun function. That's in this case. Your compiler may be doing something totally different. But the bottom line is: the implementation can do what it likes as long as it doesn't violate the standard.
That's the code from optimisation level 0, by the way, and it gives a difference of 48. When I use gcc's insane optimisation level 3, I get a difference of 4. Again, perfectly acceptable, gcc usually does some pretty impressive optimisations at that level.
So lets say I have this code
int my_static_int = 4;
func(&my_static_int);
I passed the function a pointer to my_static_int, obviously. But what happens when the code is compiled? Avenue I've considered:
1) When you declare a non-pointer variable, C automatically creates its pointer and does something internally like typedefs my_static_int to be *(internal_reference)
Anyway, I hope that my question is descriptive enough
Pointers are just a term to help us humans understand what's going on.
The & operator when used with a variable simply means address of. No "pointer" is created at runtime, you are simply passing in the address of the variable into the function.
If you have:
int x = 3;
int* p = &x;
Then p is a variable which holds a memory address. Inside that memory address is an int.
If you really want to know how the code looks under the covers, you have to get the compiler to generate the assembler code (gcc can do this with the -S option).
When you truly grok C and pointers at their deepest level, you'll realise that it's just the address of the variable being passed in rather than the value of the variable. There's no need for creating extra memory to hold a pointer since the pointer is moved directly from the code to the stack (the address will probably have been set either at link time or load time, not run time).
There's also no need for internal type creation since the compiled code already knows the type and how to manipulate it.
Keeping in mind that this is implementation-specific, consider the following code:
int my_static_int = 4;
static void func (int *x) {
*x = *x + 7;
}
int main (void) {
func(&my_static_int);
return 0;
}
which, when compiled with gcc -S to get the assembler, produces:
.file "qq.c"
.globl _my_static_int
.data
.align 4
_my_static_int:
.long 4
.text
.def _func; .scl 3; .type 32; .endef
_func:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax
movl 8(%ebp), %edx
movl (%edx), %edx
addl $7, %edx
movl %edx, (%eax)
popl %ebp
ret
.def ___main; .scl 2; .type 32; .endef
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
andl $-16, %esp
movl $0, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
movl %eax, -4(%ebp)
movl -4(%ebp), %eax
call __alloca
call ___main
movl $_my_static_int, (%esp)
call _func
movl $0, %eax
leave
ret
The important bit is these sections:
movl $_my_static_int, (%esp) ; load address of variable onto stack.
call _func ; call the function.
:
movl 8(%ebp), %eax ; get passed parameter (the address of the var) into eax
movl 8(%ebp), %edx ; and also into edx.
movl (%edx), %edx ; get the value from the address (dereference).
addl $7, %edx ; add 7 to it.
movl %edx, (%eax) ; and put it back into the same address.
Hence the address is passed, and used to get at the variable.
When the code is compiled, function func receives the address of your my_static_int variable as parameter. Nothing else.
There no need to create any implicit pointers when you declare a non-pointer variable. It is not clear from your question how you came to this weird idea.
Why not look at the assembly output? You can do this with gcc using the -S option, or (if your system uses the GNU toolchain) using the objdump -d command on the resulting object file or executable file.
The simple answer is that the object code generates a reference to the symbol where my_static_int is allocated (which is typically in the static data segment of your object module).
So the address of the variable is resolved at load time (when it is assigned a real physical address), and the loader fixes up the reference to the variable, filling it in with its address.
Wanting to see the output of the compiler (in assembly) for some C code, I wrote a simple program in C and generated its assembly file using gcc.
The code is this:
#include <stdio.h>
int main()
{
int i = 0;
if ( i == 0 )
{
printf("testing\n");
}
return 0;
}
The generated assembly for it is here (only the main function):
_main:
pushl %ebpz
movl %esp, %ebp
subl $24, %esp
andl $-16, %esp
movl $0, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
movl %eax, -8(%ebp)
movl -8(%ebp), %eax
call __alloca
call ___main
movl $0, -4(%ebp)
cmpl $0, -4(%ebp)
jne L2
movl $LC0, (%esp)
call _printf
L2:
movl $0, %eax
leave
ret
I am at an absolute loss to correlate the C code and assembly code. All that the code has to do is store 0 in a register and compare it with a constant 0 and take suitable action. But what is going on in the assembly?
Since main is special you can often get better results by doing this type of thing in another function (preferably in it's own file with no main). For example:
void foo(int x) {
if (x == 0) {
printf("testing\n");
}
}
would probably be much more clear as assembly. Doing this would also allow you to compile with optimizations and still observe the conditional behavior. If you were to compile your original program with any optimization level above 0 it would probably do away with the comparison since the compiler could go ahead and calculate the result of that. With this code part of the comparison is hidden from the compiler (in the parameter x) so the compiler can't do this optimization.
What the extra stuff actually is
_main:
pushl %ebpz
movl %esp, %ebp
subl $24, %esp
andl $-16, %esp
This is setting up a stack frame for the current function. In x86 a stack frame is the area between the stack pointer's value (SP, ESP, or RSP for 16, 32, or 64 bit) and the base pointer's value (BP, EBP, or RBP). This is supposedly where local variables live, but not really, and explicit stack frames are optional in most cases. The use of alloca and/or variable length arrays would require their use, though.
This particular stack frame construction is different than for non-main functions because it also makes sure that the stack is 16 byte aligned. The subtraction from ESP increases the stack size by more than enough to hold local variables and the andl effectively subtracts from 0 to 15 from it, making it 16 byte aligned. This alignment seems excessive except that it would force the stack to also start out cache aligned as well as word aligned.
movl $0, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
movl %eax, -8(%ebp)
movl -8(%ebp), %eax
call __alloca
call ___main
I don't know what all this does. alloca increases the stack frame size by altering the value of the stack pointer.
movl $0, -4(%ebp)
cmpl $0, -4(%ebp)
jne L2
movl $LC0, (%esp)
call _printf
L2:
movl $0, %eax
I think you know what this does. If not, the movl just befrore the call is moving the address of your string into the top location of the stack so that it may be retrived by printf. It must be passed on the stack so that printf can use it's address to infer the addresses of printf's other arguments (if any, which there aren't in this case).
leave
This instruction removes the stack frame talked about earlier. It is essentially movl %ebp, %esp followed by popl %ebp. There is also an enter instruction which can be used to construct stack frames, but gcc didn't use it. When stack frames aren't explicitly used, EBP may be used as a general puropose register and instead of leave the compiler would just add the stack frame size to the stack pointer, which would decrease the stack size by the frame size.
ret
I don't need to explain this.
When you compile with optimizations
I'm sure you will recompile all fo this with different optimization levels, so I will point out something that may happen that you will probably find odd. I have observed gcc replacing printf and fprintf with puts and fputs, respectively, when the format string did not contain any % and there were no additional parameters passed. This is because (for many reasons) it is much cheaper to call puts and fputs and in the end you still get what you wanted printed.
Don't worry about the preamble/postamble - the part you're interested in is:
movl $0, -4(%ebp)
cmpl $0, -4(%ebp)
jne L2
movl $LC0, (%esp)
call _printf
L2:
It should be pretty self-evident as to how this correlates with the original C code.
The first part is some initialization code, which does not make any sense in the case of your simple example. This code would be removed with an optimization flag.
The last part can be mapped to C code:
movl $0, -4(%ebp) // put 0 into variable i (located at -4(%ebp))
cmpl $0, -4(%ebp) // compare variable i with value 0
jne L2 // if they are not equal, skip to after the printf call
movl $LC0, (%esp) // put the address of "testing\n" at the top of the stack
call _printf // do call printf
L2:
movl $0, %eax // return 0 (calling convention: %eax has the return code)
Well, much of it is the overhead associated with the function. main() is just a function like any other, so it has to store the return address on the stack at the start, set up the return value at the end, etc.
I would recommend using GCC to generate mixed source code and assembler which will show you the assembler generated for each sourc eline.
If you want to see the C code together with the assembly it was converted to, use a command line like this:
gcc -c -g -Wa,-a,-ad [other GCC options] foo.c > foo.lst
See http://www.delorie.com/djgpp/v2faq/faq8_20.html
On linux, just use gcc. On Windows down load Cygwin http://www.cygwin.com/
Edit - see also this question Using GCC to produce readable assembly?
and http://oprofile.sourceforge.net/doc/opannotate.html
You need some knowledge about Assembly Language to understand assembly garneted by C compiler.
This tutorial might be helpful
See here more information. You can generate the assembly code with C comments for better understanding.
gcc -g -Wa,-adhls your_c_file.c > you_asm_file.s
This should help you a little.