Вопрос

I'm trying to figure out exactly what is going on with the following assembly code. Can someone go down line by line and explain what is happening? I input what I think is happening (see comments) but need clarification.

        .file   "testcalc.c"
        .section        .rodata.str1.1,"aMS",@progbits,1
.LC0:
        .string "x=%d, y=%d, z=%d, result=%d\n"
        .text
.globl main
        .type   main, @function
main:
        leal    4(%esp), %ecx   // establish stack frame
        andl    $-16, %esp      // decrement %esp by 16, align stack
        pushl   -4(%ecx)     // push original stack pointer
        pushl   %ebp     // save base pointer
        movl    %esp, %ebp     // establish stack frame 
        pushl   %ecx         // save to ecx
        subl    $36, %esp      // alloc 36 bytes for local vars
        movl    $11, 8(%esp)     // store 11 in z
        movl    $6, 4(%esp)      // store 6 in y 
        movl    $2, (%esp)    // store 2 in x
        call    calc         // function call to calc
        movl    %eax, 20(%esp)  // %esp + 20 into %eax
        movl    $11, 16(%esp)  // WHAT
        movl    $6, 12(%esp)  // WHAT
        movl    $2, 8(%esp)  // WHAT
        movl    $.LC0, 4(%esp)  // WHAT?!?!
        movl    $1, (%esp) // move result into address of %esp
        call    __printf_chk  // call printf function
        addl    $36, %esp  // WHAT?
        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

Original code:

#include <stdio.h>

int calc(int x, int y, int z);

int main()
{
        int x = 2;
        int y = 6;
        int z = 11;
        int result;

        result = calc(x,y,z);

        printf("x=%d, y=%d, z=%d, result=%d\n",x,y,z,result);
}
Это было полезно?

Решение

You didn't show the compilation command, that could be useful, but it seems that you have optimizations enabled, so there are actually no space for local variables, they are optimized out:

main:
        leal    4(%esp), %ecx   
        andl    $-16, %esp      
        pushl   -4(%ecx)     
        pushl   %ebp     
        movl    %esp, %ebp

All this code above set the stack frame. Since it is the main it is a bit different from a standard stack frame: it ensures the alignment of the stack with andl $-16, %esp, just in case.

        pushl   %ecx

It saves the original value of esp before the alignment correction, to restore it at the end.

        subl    $36, %esp

It allocates 36 bytes of stack space, not for local variables but for calling parameters.

        movl    $11, 8(%esp)
        movl    $6, 4(%esp)
        movl    $2, (%esp)

It sets the arguments for calling calc from right to left, that is, the constants, (2, 6, 11).

        call    calc         // function call to calc

It calls function calc with the arguments pointed to by esp.

        movl    %eax, 20(%esp)
        movl    $11, 16(%esp)
        movl    $6, 12(%esp)
        movl    $2, 8(%esp)
        movl    $.LC0, 4(%esp)
        movl    $1, (%esp)

These are the arguments for calling __printf_chk, from right to left: (1, .LC0, 2, 6, 11, %eax), where %eax is the return value of calc() (remember, no local variables!) and .LC0 is the address of the literal string, look at these lines at the top of the assembly:

.LC0:
        .string "x=%d, y=%d, z=%d, result=%d\n"

But what about that mysterious 1?. Well, in Ubuntu the standard compilation options (-D_FORTIFY_SOURCE) will make printf an inline function that forwards to __printf_chk(1, ...) or something like that, that does extra checks to the arguments.

        call    __printf_chk

This is the call to the printf substitute function.

        addl    $36, %esp

This removes the 36 bytes added to the stack with subl $36, %esp.

        popl    %ecx 

This restores the possibly unaligned stack pointer into ecx.

        popl    %ebp
        leal    -4(%ecx), %esp

This restores the previous stack frame.

        ret

And this returns without a value, because you didn't write a return for main.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top