【发布时间】:2014-04-23 20:34:16
【问题描述】:
我有一个简单的函数序言(对于 C 程序的 main(),没有参数),如下所示:
0x8048384 push ebp
0x8048385 mov ebp,esp
0x8048387 sub esp,0x18
0x804838a and esp,0xfffffff0
0x804838d mov eax,0x0
0x8048392 sub esp,eax
我很好奇,将 eax 设置为 0 然后从 esp 中减去它的目的是什么?这似乎是浪费的指令。是否还有其他 gcc 生成的函数序言的示例,其中这将具有更多意义(或者 eax 的值不是 0)?
提前致谢!
编辑:整个 C 程序(来自“探索的艺术”一书)如下。它仅使用 -g 选项编译,使用 gcc 3.3.6(是的,很旧,但它来自虚拟机映像)。这应该是关于堆栈的一课。
void test_function(int a, int b, int c, int d)
{
int flag;
char buffer[10];
flag 31337;
buffer[0] = 'A';
}
int main()
{
test_function(1, 2, 3, 4);
}
提供编辑#2 反汇编(gcc -g -S -masm=intel):
.file "stack_example.c"
.intel_syntax
.file 1 "stack_example.c"
.section .debug_abbrev,"",@progbits
.Ldebug_abbrev0:
.section .debug_info,"",@progbits
.Ldebug_info0:
.section .debug_line,"",@progbits
.Ldebug_line0:
.text
.Ltext0:
.globl test_function
.type test_function, @function
test_function:
.LFB3:
.loc 1 1 0
push %ebp
.LCFI0:
mov %ebp, %esp
.LCFI1:
sub %esp, 40
.LCFI2:
.loc 1 5 0
.LBB2:
mov DWORD PTR [%ebp-12], 31337
.loc 1 6 0
mov BYTE PTR [%ebp-40], 65
.loc 1 7 0
leave
ret
.LBE2:
.LFE3:
.size test_function, .-test_function
.globl main
.type main, @function
main:
.LFB5:
.loc 1 9 0
push %ebp
.LCFI3:
mov %ebp, %esp
.LCFI4:
sub %esp, 24
.LCFI5:
and %esp, -16
mov %eax, 0
sub %esp, %eax
.loc 1 10 0
mov DWORD PTR [%esp+12], 4
mov DWORD PTR [%esp+8], 3
mov DWORD PTR [%esp+4], 2
mov DWORD PTR [%esp], 1
call test_function
.loc 1 11 0
leave
ret
.LFE5:
.size main, .-main
.section .debug_frame,"",@progbits
.Lframe0:
.long .LECIE0-.LSCIE0
.LSCIE0:
.long 0xffffffff
.byte 0x1
.string ""
.uleb128 0x1
.sleb128 -4
.byte 0x8
.byte 0xc
.uleb128 0x4
.uleb128 0x4
.byte 0x88
.uleb128 0x1
.align 4
.LECIE0:
.LSFDE0:
.long .LEFDE0-.LASFDE0
.LASFDE0:
.long .Lframe0
.long .LFB3
.long .LFE3-.LFB3
.byte 0x4
.long .LCFI0-.LFB3
.byte 0xe
.uleb128 0x8
.byte 0x85
.uleb128 0x2
.byte 0x4
.long .LCFI1-.LCFI0
.byte 0xd
.uleb128 0x5
.align 4
.LEFDE0:
.LSFDE2:
.long .LEFDE2-.LASFDE2
.LASFDE2:
.long .Lframe0
.long .LFB5
.long .LFE5-.LFB5
.byte 0x4
.long .LCFI3-.LFB5
.byte 0xe
.uleb128 0x8
.byte 0x85
.uleb128 0x2
.byte 0x4
.long .LCFI4-.LCFI3
.byte 0xd
.uleb128 0x5
.align 4
.LEFDE2:
.text
.Letext0:
.section .debug_info
.long 0x118
.value 0x2
.long .Ldebug_abbrev0
.byte 0x4
.uleb128 0x1
.long .Ldebug_line0
.long .Letext0
.long .Ltext0
.string "stack_example.c"
.string "/home/booksrc"
.string "GNU C 3.3.6 (Ubuntu 1:3.3.6-15ubuntu1)"
.byte 0x1
.uleb128 0x2
.long 0xd5
.byte 0x1
.string "test_function"
.byte 0x1
.byte 0x1
.byte 0x1
.long .LFB3
.long .LFE3
.byte 0x1
.byte 0x55
.uleb128 0x3
.string "a"
.byte 0x1
.byte 0x1
.long 0xd5
.byte 0x2
.byte 0x91
.sleb128 8
.uleb128 0x3
.string "b"
.byte 0x1
.byte 0x1
.long 0xd5
.byte 0x2
.byte 0x91
.sleb128 12
.uleb128 0x3
.string "c"
.byte 0x1
.byte 0x1
.long 0xd5
.byte 0x2
.byte 0x91
.sleb128 16
.uleb128 0x3
.string "d"
.byte 0x1
.byte 0x1
.long 0xd5
.byte 0x2
.byte 0x91
.sleb128 20
.uleb128 0x4
.string "flag"
.byte 0x1
.byte 0x2
.long 0xd5
.byte 0x2
.byte 0x91
.sleb128 -12
.uleb128 0x4
.string "buffer"
.byte 0x1
.byte 0x3
.long 0xdc
.byte 0x2
.byte 0x91
.sleb128 -40
.byte 0x0
.uleb128 0x5
.string "int"
.byte 0x4
.byte 0x5
.uleb128 0x6
.long 0xec
.long 0xfc
.uleb128 0x7
.long 0xec
.byte 0x9
.byte 0x0
.uleb128 0x5
.string "unsigned int"
.byte 0x4
.byte 0x7
.uleb128 0x5
.string "char"
.byte 0x1
.byte 0x6
.uleb128 0x8
.byte 0x1
.string "main"
.byte 0x1
.byte 0x9
.long 0xd5
.long .LFB5
.long .LFE5
.byte 0x1
.byte 0x55
.byte 0x0
.section .debug_abbrev
.uleb128 0x1
.uleb128 0x11
.byte 0x1
.uleb128 0x10
.uleb128 0x6
.uleb128 0x12
.uleb128 0x1
.uleb128 0x11
.uleb128 0x1
.uleb128 0x3
.uleb128 0x8
.uleb128 0x1b
.uleb128 0x8
.uleb128 0x25
.uleb128 0x8
.uleb128 0x13
.uleb128 0xb
.byte 0x0
.byte 0x0
.uleb128 0x2
.uleb128 0x2e
.byte 0x1
.uleb128 0x1
.uleb128 0x13
.uleb128 0x3f
.uleb128 0xc
.uleb128 0x3
.uleb128 0x8
.uleb128 0x3a
.uleb128 0xb
.uleb128 0x3b
.uleb128 0xb
.uleb128 0x27
.uleb128 0xc
.uleb128 0x11
.uleb128 0x1
.uleb128 0x12
.uleb128 0x1
.uleb128 0x40
.uleb128 0xa
.byte 0x0
.byte 0x0
.uleb128 0x3
.uleb128 0x5
.byte 0x0
.uleb128 0x3
.uleb128 0x8
.uleb128 0x3a
.uleb128 0xb
.uleb128 0x3b
.uleb128 0xb
.uleb128 0x49
.uleb128 0x13
.uleb128 0x2
.uleb128 0xa
.byte 0x0
.byte 0x0
.uleb128 0x4
.uleb128 0x34
.byte 0x0
.uleb128 0x3
.uleb128 0x8
.uleb128 0x3a
.uleb128 0xb
.uleb128 0x3b
.uleb128 0xb
.uleb128 0x49
.uleb128 0x13
.uleb128 0x2
.uleb128 0xa
.byte 0x0
.byte 0x0
.uleb128 0x5
.uleb128 0x24
.byte 0x0
.uleb128 0x3
.uleb128 0x8
.uleb128 0xb
.uleb128 0xb
.uleb128 0x3e
.uleb128 0xb
.byte 0x0
.byte 0x0
.uleb128 0x6
.uleb128 0x1
.byte 0x1
.uleb128 0x1
.uleb128 0x13
.uleb128 0x49
.uleb128 0x13
.byte 0x0
.byte 0x0
.uleb128 0x7
.uleb128 0x21
.byte 0x0
.uleb128 0x49
.uleb128 0x13
.uleb128 0x2f
.uleb128 0xb
.byte 0x0
.byte 0x0
.uleb128 0x8
.uleb128 0x2e
.byte 0x0
.uleb128 0x3f
.uleb128 0xc
.uleb128 0x3
.uleb128 0x8
.uleb128 0x3a
.uleb128 0xb
.uleb128 0x3b
.uleb128 0xb
.uleb128 0x49
.uleb128 0x13
.uleb128 0x11
.uleb128 0x1
.uleb128 0x12
.uleb128 0x1
.uleb128 0x40
.uleb128 0xa
.byte 0x0
.byte 0x0
.byte 0x0
.section .debug_pubnames,"",@progbits
.long 0x29
.value 0x2
.long .Ldebug_info0
.long 0x11c
.long 0x63
.string "test_function"
.long 0x104
.string "main"
.long 0x0
.section .debug_aranges,"",@progbits
.long 0x1c
.value 0x2
.long .Ldebug_info0
.byte 0x4
.byte 0x0
.value 0x0
.value 0x0
.long .Ltext0
.long .Letext0-.Ltext0
.long 0x0
.long 0x0
.section .note.GNU-stack,"",@progbits
.ident "GCC: (GNU) 3.3.6 (Ubuntu 1:3.3.6-15ubuntu1)"
【问题讨论】:
-
您使用了什么优化级别?可能是编译器生成了用于创建堆栈帧(用于自动存储)的“样板”,但由于您没有声明局部变量,因此大小为 0。这会随着优化(死代码消除)而消失。跨度>
-
根据这个答案,stackoverflow.com/questions/11886429/…,它将它与 SSE 指令要求的 16 字节边界对齐。有关更多信息,请参阅链接的答案。
-
'and esp,0xfffffff0' 正在进行对齐,OP 询问的是 'mov eax,0x0' 和 'sub esp,eax'。
-
@amdn - 我想你可能是对的。我只用 -g 选项编译了这个(没有优化)。不过,我很好奇 gcc 何时会给 eax 一个非“0”的值。这两条指令似乎没用,因为如果您需要为变量分配更多内存,您可以使用 sub esp 指令来完成。
-
gcc 似乎认识到这些局部变量未被使用,因此它没有为它们分配存储空间。尝试使用 -O3 进行编译,看看它的作用。