简体   繁体   English

为什么GCC产生以下asm输出?

[英]Why does GCC produce the following asm output?

I don't understand why gcc -S -m32 produces these particular lines of code: 我不明白为什么gcc -S -m32产生这些特定的代码行:

movl    %eax, 28(%esp)
movl    $desc, 4(%esp)
movl    28(%esp), %eax
movl    %eax, (%esp)
call    sort_gen_asm

My question is why %eax is pushed and then popped? 我的问题是为什么%eax被推,然后弹出? And why movl used instead of pushl and popl respectively? 为什么movl用来代替pushlpopl分别? Is it faster? 它更快吗? Is there some coding convention I don't yet know? 是否有一些我还不知道的编码约定? I've just started looking at asm-output closely, so I don't know much. 我刚刚开始密切关注asm-output,所以我不太了解。

The C code: C代码:

void print_array(int *data, size_t sz);
void sort_gen_asm(array_t*, comparer_t);

int main(int argc, char *argv[]) {
    FILE *file;
    array_t *array;

    file = fopen("test", "rb");
    if (file == NULL) { 
        err(EXIT_FAILURE, NULL);
    }   

    array = array_get(file);
    sort_gen_asm(array, desc); 
    print_array(array->data, array->sz);

    array_destroy(array);
    fclose(file); 

    return 0;
}

It gives this output: 它给出了这个输出:

    .file   "main.c"
    .section    .rodata
.LC0:
    .string "rb"
.LC1:
    .string "test"
    .text
    .globl  main
    .type   main, @function
main:
.LFB2:
    .cfi_startproc
    pushl   %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    andl    $-16, %esp
    subl    $32, %esp
    movl    $.LC0, 4(%esp)
    movl    $.LC1, (%esp)
    call    fopen
    movl    %eax, 24(%esp)
    cmpl    $0, 24(%esp)
    jne .L2
    movl    $0, 4(%esp)
    movl    $1, (%esp)
    call    err
.L2:
    movl    24(%esp), %eax
    movl    %eax, (%esp)
    call    array_get
    movl    %eax, 28(%esp)
    movl    $desc, 4(%esp)
    movl    28(%esp), %eax
    movl    %eax, (%esp)
    call    sort_gen_asm
    movl    28(%esp), %eax
    movl    4(%eax), %edx
    movl    28(%esp), %eax
    movl    (%eax), %eax
    movl    %edx, 4(%esp)
    movl    %eax, (%esp)
    call    print_array
    movl    28(%esp), %eax
    movl    %eax, (%esp)
    call    array_destroy
    movl    24(%esp), %eax
    movl    %eax, (%esp)
    call    fclose
    movl    $0, %eax
    leave
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
.LFE2:
    .size   main, .-main
    .ident  "GCC: (Ubuntu/Linaro 4.8.1-10ubuntu8) 4.8.1"
    .section    .note.GNU-stack,"",@progbits

The save / load of eax is because you did not compile with optimizations. eax的保存/加载是因为您没有使用优化进行编译。 So any read/write of a variable will emit a read/write of a memory address. 因此,任何读/写变量都会发出内存地址的读/写。

Actually, for (almost) any line of code you will be able to identify the exact piece of assembler code resulting from it (let me advise you to compile with gcc -g -c -O0 and then objdump -S file.o ): 实际上,对于(几乎)任何代码行,您将能够识别由它产生的确切的汇编代码片段(让我建议您使用gcc -g -c -O0然后使用objdump -S file.o进行编译):

#array = array_get(file); 
call array_get
movl    %eax, 28(%esp) #write array

#sort_gen_asm(array, desc); 
movl    28(%esp), %eax  #read array
movl    %eax, (%esp)
...

About not pushing/poping, it is a standard zero-cost optimization . 关于不推/弹,这是标准的零成本优化 Instead of push/pop every time you want to call a function you just substract the maximum needed space to esp at the beginning of the function and then save your function arguments at the bottom of the empty space. 每次要调用函数时,只需将最大所需空间减去esp函数的开头,然后将函数参数保存在空白的底部,而不是每次调用函数。 There are a lot of advantages: faster code (no changing esp ), it doesn't need to compute the argument in any particular order, and the esp will need to be substracted anyway for the local variables space. 有很多优点:更快的代码(不改变esp ),它不需要以任何特定的顺序计算参数,并且esp将需要为局部变量空间减去。

Some things have to do with calling conventions. 有些事情与调用约定有关。 Others with optimisations. 其他人则有优化。

sort_gen_asm seems to use cdecl calling convention which requires it's arguments to be pushed onto the stack in reverse order. sort_gen_asm似乎使用cdecl调用约定,它要求将参数以相反的顺序压入堆栈。 thus: 从而:

movl    $desc, 4(%esp)
movl    %eax, (%esp)

The other moves are partially unoptimised compiler routines: 其他步骤是部分未经优化的编译器例程:

movl    %eax, 28(%esp) # save contents of %eax on the stack before calling
movl    28(%esp), %eax # retrieve saved 28(%esp) in order to prepare it as an argument
                       # Unoptimised compiler seems to have forgotten that it's
                       # still in the register

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM