理解由简单C程序生成的汇编代码
我试图通过使用gdb的反汇编程序检查一个简单C程序来理解它的汇编级代码 以下是C代码:理解由简单C程序生成的汇编代码,c,linux,assembly,stack,disassembly,C,Linux,Assembly,Stack,Disassembly,我试图通过使用gdb的反汇编程序检查一个简单C程序来理解它的汇编级代码 以下是C代码: #include <stdio.h> void function(int a, int b, int c) { char buffer1[5]; char buffer2[10]; } void main() { function(1,2,3); } 我正在寻找以下问题的答案: 地址是如何工作的,我的意思是(main+0),(main+1),(main+3) 总的来说,为什么
#include <stdio.h>
void function(int a, int b, int c) {
char buffer1[5];
char buffer2[10];
}
void main() {
function(1,2,3);
}
我正在寻找以下问题的答案:
main+0
、main+1
、main+3
、main+6
等“奇怪”地址的原因是,每条指令占用的字节数可变。例如:
main+0: push %ebp
是一条单字节指令,因此下一条指令位于main+1
。另一方面,
main+3: and $0xfffffff0,%esp
是一条三字节指令,因此之后的下一条指令位于main+6
而且,由于您在注释中询问为什么movl
似乎采用了可变的字节数,对此的解释如下
指令长度不仅取决于操作码(如movl
),还取决于操作数的寻址模式(操作码所操作的对象)。我没有专门检查你的代码,但我怀疑
movl $0x1,(%esp)
指令可能更短,因为不涉及偏移量-它只使用esp
作为地址。鉴于:
movl $0x2,0x4(%esp)
需要movl$0x1、(%esp)
所做的一切,以及偏移量0x4
的额外字节
事实上,这里有一个调试会话,显示了我的意思:
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.
c:\pax> debug
-a
0B52:0100 mov word ptr [di],7
0B52:0104 mov word ptr [di+2],8
0B52:0109 mov word ptr [di+0],7
0B52:010E
-u100,10d
0B52:0100 C7050700 MOV WORD PTR [DI],0007
0B52:0104 C745020800 MOV WORD PTR [DI+02],0008
0B52:0109 C745000700 MOV WORD PTR [DI+00],0007
-q
c:\pax> _
您可以看到,第二条带偏移量的指令实际上与第一条不带偏移量的指令不同。它长了一个字节(5个字节而不是4个字节,以保持偏移量),并且实际上具有不同的编码c745
,而不是c705
您还可以看到,您可以用两种不同的方式对第一条指令和第三条指令进行编码,但它们基本上做相同的事情
和$0xfffff0,%esp
指令是一种强制esp
位于特定边界上的方法。这用于确保变量的正确对齐。现代处理器上的许多内存访问如果遵循对齐规则(例如,4字节值必须与4字节边界对齐),将更加高效。如果不遵守这些规则,一些现代处理器甚至会出现故障
执行此指令后,将保证esp
小于或等于其先前的值,并与16字节边界对齐
gs:
前缀仅仅意味着使用gs
段寄存器来访问内存,而不是默认值
指令mov%eax,-0xc(%ebp)
意味着获取ebp
寄存器的内容,减去12(0xc
),然后将eax
的值放入该内存位置
重新解释代码。您的
函数
函数基本上是一个大的禁止操作。生成的程序集仅限于堆栈帧设置和拆卸,以及一些使用上述%gs:14
内存位置的堆栈帧损坏检查
它将该位置的值(可能类似于0xdeadbeef
)加载到堆栈帧中,执行其工作,然后检查堆栈以确保其未损坏
在这种情况下,它的工作毫无意义。所以你看到的只是功能管理的东西
堆栈设置发生在函数+0
和函数+12
之间。之后的所有工作都是在eax
中设置返回代码,并拆除堆栈框架,包括损坏检查
类似地,main
由堆栈框架设置组成,按下函数的参数,调用函数,拆下堆栈框架并退出
注释已插入到以下代码中:
0x08048428 <main+0>: push %ebp ; save previous value.
0x08048429 <main+1>: mov %esp,%ebp ; create new stack frame.
0x0804842b <main+3>: and $0xfffffff0,%esp ; align to boundary.
0x0804842e <main+6>: sub $0x10,%esp ; make space on stack.
0x08048431 <main+9>: movl $0x3,0x8(%esp) ; push values for function.
0x08048439 <main+17>: movl $0x2,0x4(%esp)
0x08048441 <main+25>: movl $0x1,(%esp)
0x08048448 <main+32>: call 0x8048404 <function> ; and call it.
0x0804844d <main+37>: leave ; tear down frame.
0x0804844e <main+38>: ret ; and exit.
0x08048404 <func+0>: push %ebp ; save previous value.
0x08048405 <func+1>: mov %esp,%ebp ; create new stack frame.
0x08048407 <func+3>: sub $0x28,%esp ; make space on stack.
0x0804840a <func+6>: mov %gs:0x14,%eax ; get sentinel value.
0x08048410 <func+12>: mov %eax,-0xc(%ebp) ; put on stack.
0x08048413 <func+15>: xor %eax,%eax ; set return code 0.
0x08048415 <func+17>: mov -0xc(%ebp),%eax ; get sentinel from stack.
0x08048418 <func+20>: xor %gs:0x14,%eax ; compare with actual.
0x0804841f <func+27>: je <func+34> ; jump if okay.
0x08048421 <func+29>: call <_stk_chk_fl> ; otherwise corrupted stack.
0x08048426 <func+34>: leave ; tear down frame.
0x08048427 <func+35>: ret ; and exit.
然后sentinel将被覆盖,函数末尾的检查将检测到这一点,调用failure函数让您知道,然后可能会中止,以避免任何其他问题
如果将0xdeadbeef
放在堆栈上,并将其更改为其他内容,则带有0xdeadbeef
的xor
将产生一个非零值,该值在带有je
指令的代码中检测到
此处对相关位进行了解释:
mov %gs:0x14,%eax ; get sentinel value.
mov %eax,-0xc(%ebp) ; put on stack.
;; Weave your function
;; magic here.
mov -0xc(%ebp),%eax ; get sentinel back from stack.
xor %gs:0x14,%eax ; compare with original value.
je stack_ok ; zero/equal means no corruption.
call stack_bad ; otherwise corrupted stack.
stack_ok: leave ; tear down frame.
和平已经给出了一个明确的答案。然而,为了完整性,我想我应该添加一个注释,让GCC本身向您展示它生成的程序集
GCC的-S
选项告诉它停止编译并将程序集写入文件。通常,它要么将该文件传递给汇编程序,要么对某些目标直接将对象文件写入自身
对于问题中的示例代码:
#include <stdio.h>
void function(int a, int b, int c) {
char buffer1[5];
char buffer2[10];
}
void main() {
function(1,2,3);
}
有一点很明显,我的GCC(GCC(GCC)3.4.5(mingw vista special r3))默认情况下不包含堆栈检查代码。我想象有一个命令行选项,或者如果我有时间将我的MinGW安装升级到一个更新的GCC,它可能会这样做
编辑:在Pax的推动下,这里是另一种让GCC做更多工作的方法
C:\Documents and Settings\Ross\My Documents\testing>gcc -Wa,-al q3654898.c
q3654898.c: In function `main':
q3654898.c:8: warning: return type of 'main' is not `int'
GAS LISTING C:\DOCUME~1\Ross\LOCALS~1\Temp/ccLg8pWC.s page 1
1 .file "q3654898.c"
2 .text
3 .globl _function
4 .def _function; .scl 2; .type
32; .endef
5 _function:
6 0000 55 pushl %ebp
7 0001 89E5 movl %esp, %ebp
8 0003 83EC28 subl $40, %esp
9 0006 C9 leave
10 0007 C3 ret
11 .def ___main; .scl 2; .type
32; .endef
12 .globl _main
13 .def _main; .scl 2; .type 32;
.endef
14 _main:
15 0008 55 pushl %ebp
16 0009 89E5 movl %esp, %ebp
17 000b 83EC18 subl $24, %esp
18 000e 83E4F0 andl $-16, %esp
19 0011 B8000000 movl $0, %eax
19 00
20 0016 83C00F addl $15, %eax
21 0019 83C00F addl $15, %eax
22 001c C1E804 shrl $4, %eax
23 001f C1E004 sall $4, %eax
24 0022 8945FC movl %eax, -4(%ebp)
25 0025 8B45FC movl -4(%ebp), %eax
26 0028 E8000000 call __alloca
26 00
27 002d E8000000 call ___main
27 00
28 0032 C7442408 movl $3, 8(%esp)
28 03000000
29 003a C7442404 movl $2, 4(%esp)
29 02000000
30 0042 C7042401 movl $1, (%esp)
30 000000
31 0049 E8B2FFFF call _function
31 FF
32 004e C9 leave
33 004f C3 ret
C:\Documents and Settings\Ross\My Documents\testing>
C:\Documents and Settings\Ross\My Documents\testing>gcc-Wa,-al q3654898.C
q3654898.c:在函数“main”中:
q3654898.c:8:警告:“main”的返回类型不是“int”
气体清单C:\DOCUME~1\Ross\LOCALS~1\Temp/ccLg8pWC.s第1页
1.文件“q3654898.c”
2.文本
3.全局函数
4.定义函数。症状自评量表2。类型
32; .恩德夫
5_功能:
6 0000 55%推力ebp
7 0001 89E5
#include <stdio.h>
void function(int a, int b, int c) {
char buffer1[5];
char buffer2[10];
}
void main() {
function(1,2,3);
}
.file "q3654898.c"
.text
.globl _function
.def _function; .scl 2; .type 32; .endef
_function:
pushl %ebp
movl %esp, %ebp
subl $40, %esp
leave
ret
.def ___main; .scl 2; .type 32; .endef
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
andl $-16, %esp
movl $0, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
movl %eax, -4(%ebp)
movl -4(%ebp), %eax
call __alloca
call ___main
movl $3, 8(%esp)
movl $2, 4(%esp)
movl $1, (%esp)
call _function
leave
ret
C:\Documents and Settings\Ross\My Documents\testing>gcc -Wa,-al q3654898.c
q3654898.c: In function `main':
q3654898.c:8: warning: return type of 'main' is not `int'
GAS LISTING C:\DOCUME~1\Ross\LOCALS~1\Temp/ccLg8pWC.s page 1
1 .file "q3654898.c"
2 .text
3 .globl _function
4 .def _function; .scl 2; .type
32; .endef
5 _function:
6 0000 55 pushl %ebp
7 0001 89E5 movl %esp, %ebp
8 0003 83EC28 subl $40, %esp
9 0006 C9 leave
10 0007 C3 ret
11 .def ___main; .scl 2; .type
32; .endef
12 .globl _main
13 .def _main; .scl 2; .type 32;
.endef
14 _main:
15 0008 55 pushl %ebp
16 0009 89E5 movl %esp, %ebp
17 000b 83EC18 subl $24, %esp
18 000e 83E4F0 andl $-16, %esp
19 0011 B8000000 movl $0, %eax
19 00
20 0016 83C00F addl $15, %eax
21 0019 83C00F addl $15, %eax
22 001c C1E804 shrl $4, %eax
23 001f C1E004 sall $4, %eax
24 0022 8945FC movl %eax, -4(%ebp)
25 0025 8B45FC movl -4(%ebp), %eax
26 0028 E8000000 call __alloca
26 00
27 002d E8000000 call ___main
27 00
28 0032 C7442408 movl $3, 8(%esp)
28 03000000
29 003a C7442404 movl $2, 4(%esp)
29 02000000
30 0042 C7042401 movl $1, (%esp)
30 000000
31 0049 E8B2FFFF call _function
31 FF
32 004e C9 leave
33 004f C3 ret
C:\Documents and Settings\Ross\My Documents\testing>
void function(int a, int b, int c) {
char buffer1[5];
char buffer2[10];
}
/* corrected calling convention of main() */
int main() {
function(1,2,3);
return 0;
}
.globl _function
_function:
pushl %ebp
movl %esp, %ebp
pushl %ebx
subl $36, %esp
call L4
"L00000000001$pb":
L4:
popl %ebx
leal L___stack_chk_guard$non_lazy_ptr-"L00000000001$pb"(%ebx), %eax
movl (%eax), %eax
movl (%eax), %edx
movl %edx, -12(%ebp)
xorl %edx, %edx
leal L___stack_chk_guard$non_lazy_ptr-"L00000000001$pb"(%ebx), %eax
movl (%eax), %eax
movl -12(%ebp), %edx
xorl (%eax), %edx
je L3
call ___stack_chk_fail
L3:
addl $36, %esp
popl %ebx
leave
ret
.globl _main
_main:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl $3, 8(%esp)
movl $2, 4(%esp)
movl $1, (%esp)
call _function
movl $0, %eax
leave
ret
.text
.globl _function
_function:
pushl %ebp
movl %esp, %ebp
leave
ret
.globl _main
_main:
pushl %ebp
movl %esp, %ebp
movl $0, %eax
leave
ret