tags:

views:

187

answers:

4

im just curious about the following example

#include<stdio.h>
int test();
int test(){
     //    int a = 5;
     //    int b = a+1;
     return ;
}
int main(){
     printf("%u\n",test());
     return 0;
}

i compiled it with 'gcc -Wall -o semicolon semicolon.c' to create an executable and 'gcc -Wall -S semicolon.c' to get the assembler code which is:

    .file   "semicolon.c"
    .text
.globl test
    .type   test, @function
test:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $4, %esp
    leave
    ret
    .size   test, .-test
    .section        .rodata
 .LC0:
    .string "%u\n"
    .text
 .globl main
    .type   main, @function
 main:
    leal    4(%esp), %ecx
    andl    $-16, %esp
    pushl   -4(%ecx)
    pushl   %ebp
    movl    %esp, %ebp
    pushl   %ecx
    subl    $20, %esp
    call    test
    movl    %eax, 4(%esp)
    movl    $.LC0, (%esp)
    call    printf
    movl    $0, %eax
    addl    $20, %esp
    popl    %ecx
    popl    %ebp
    leal    -4(%ecx), %esp
    ret
    .size   main, .-main
    .ident  "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3"
    .section        .note.GNU-stack,"",@progbits

since im not such an assembler pro, i only know that printf prints what is in eax but i dont fully understand what 'movl %eax, 4(%esp)' means which i assume fills eax before calling test but what is the value then? what means 4(%esp) and what does the value of esp mean?

if i uncomment the lines in test() printf prints 6 - which is written in eax ^^

+7  A: 

The semicolon has no return value, what you have there is an "empty return", like the one used to return from void functions - so the function doesn't return anything.

This actually causes a warning when compiling:

warning: `return' with no value, in function returning non-void

And I don't see anything placed in eax before calling test.

About 4(%esp), this means taking the value from the stack pointer (esp) + 4. I.e. the one-before-last word on the stack.

Eli Bendersky
John Doe
No, it means that the value of eax is stored in [esp+4], that's perhaps some local variable on the stack
Eli Bendersky
+2  A: 

The return value of an int function is passed in the EAX register. The test function does not set the EAX register because no return value is given. The result is therefore undefined.

Tomas
so the result is not undefined, but the value found in eax, right? which is by definition called 'undefined'
John Doe
Yes, the result is the value in EAX. Since EAX is not explicitly set it's value is determined by some unknown previous operation. This is what we call 'undefined'.
Tomas
+1  A: 

A semicolon indeed has no value.

I think the correct answer is that a return <nothing> for an int function is an error, or at least has undefined behavor. That's why compiling this with -Wall yields

semi.c: In function ‘test’:
semi.c:6: warning: ‘return’ with no value, in function returning non-void

As for what the %4,esp holds... it's a location on the stack where nothing was (intentionally) stored, so it will likely return whatever junk is found at that location. This could be the last expression evaluated to variables in the function (as in your example) or something completely different. This is what "undefined" is all about. :)

Carl Smotricz
+7  A: 

Your assembly language annotated:

test:
    pushl   %ebp        # Save the frame pointer
    movl    %esp, %ebp  # Get the new frame pointer.
    subl    $4, %esp    # Allocate some local space on the stack.
    leave               # Restore the old frame pointer/stack
    ret

Note that nothing in test touches eax.

.size   test, .-test
.section        .rodata
 .LC0:
.string "%u\n"
.text
 .globl main
.type   main, @function
main:
leal    4(%esp), %ecx      # Point past the return address.
andl    $-16, %esp         # Align the stack.
pushl   -4(%ecx)           # Push the return address.
pushl   %ebp               # Save the frame pointer
movl    %esp, %ebp         # Get the new frame pointer.
pushl   %ecx               # save the old top of stack.
subl    $20, %esp          # Allocate some local space (for printf parameters and ?).
call    test               # Call test.

Note that at this point, nothing has modified eax. Whatever came into main is still here.

movl    %eax, 4(%esp)      # Save eax as a printf argument.
movl    $.LC0, (%esp)      # Send the format string.
call    printf             # Duh.
movl    $0, %eax           # Return zero from main.
addl    $20, %esp          # Deallocate local space.
popl    %ecx               # Restore the old top of stack.
popl    %ebp               # And the old frame pointer.
leal    -4(%ecx), %esp     # Fix the stack pointer,
ret

So, what gets printed out is whatever came in to main. As others have pointed out it is undefined: It depends on what the startup code (or the OS) has done to eax previously.

Richard Pennington
great explanation. to add some more info about this topic, it seems that eax and its usage on passing the value through the stack is similar for simple datatypes (int,double,char,void*,...) but as it gets into structures more of the compilers memory management comes into play. im not yet sure what happens on the stack in case of structures to understand empty return's on non void functions which should return a structure, but thats a more complex question/answer. anyway - thx
John Doe
@John: pretty much the same thing happens with structures as with `int`s and `float`s. It is called _stack trash_. Whatever happens to be in the memory that the caller reserved for the return value is what gets _returned_.
D.Shawley