[英]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
用来代替pushl
和popl
分别? 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.