我不明白为什么< code>gcc -S -m32会产生这些特定的代码行:
movl %eax, 28(%esp)
movl $desc, 4(%esp)
movl 28(%esp), %eax
movl %eax, (%esp)
call sort_gen_asm
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;
}
它给出以下输出:
.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
有些事情与调用约定有关。其他优化。
< code>sort_gen_asm似乎使用了< code>cdecl调用约定,该约定要求将其参数以相反的顺序压入堆栈。因此:
movl $desc, 4(%esp)
movl %eax, (%esp)
其他步骤是部分未优化的编译器例程:
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
eax
的保存/加载是因为您没有使用优化进行编译。因此,对变量的任何读/写都会发出对内存地址的读/写。
实际上,对于(几乎)任何一行代码,您都能够识别从中产生的汇编代码的确切部分(让我建议您用< code>gcc -g -c -O0然后用< code>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)
...
关于不推/不弹出,是标准的零成本优化。每次你想调用一个函数的时候,不用按下/弹出键,你只需要在函数的开头减去最大需要的空间,然后把你的函数参数保存在空白空间的底部。有很多优点:更快的代码(不改变< code>esp),它不需要以任何特定的顺序计算参数,并且对于局部变量空间,< code>esp无论如何都需要被减去。
我有一项任务,阐述C代码(在x86上运行)的一些看似奇怪的行为。我可以很容易地完成其他一切,但这件事真的让我困惑。 代码段1输出
我非常困惑为什么gcc会为const数组上的简单for循环生成这种(看似)非最佳代码。 结果: 我主要关心的是: 为什么无用的第一个元素比较在?这永远不会命中,也永远不会被分支回。它最终只是第一次迭代的重复代码。 < li >有没有更好的方法来编写这个非常简单的循环,这样gcc就不会产生这种奇怪的代码? < li >有没有我可以利用的编译器标志/优化?< code>O3只是展开循环,我也不希望这样
它给出的输出为“cricket”。但我不明白为什么?http://ideone.com/fteahg
我的理解是,当编写gcc样式的内联asm时,您必须非常具体和准确地了解所有的输入和输出参数(和clobbers),这样编译器就会确切地知道如何为代码分配寄存器,以及它可以对那些寄存器的值和asm代码可能读取和/或修改的任何内存假设什么。编译器使用这些信息尽可能地优化周围的代码(如果它认为内联asm对任何东西都没有影响,甚至完全删除它)。对此不够具体可能会导致不正确的行为,因为编译器是根据您的不正确
我观察到库函数,当它在循环中被调用一次时,它几乎总是产生正数。