首先编写一个简单的C语言程序,过程如图所示:
使用命令gcc -S -o 20222803.s 20222803.c -m32
可以将C语言代码文件20222803.c
反汇编出汇编语言代码文件20222803.s
,20222803.s
内容如下:
.file "20222803.c"
.text
.globl g
.type g, @function
g:
.LFB0:
.cfi_startproc
endbr32
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
call __x86.get_pc_thunk.ax
addl $_GLOBAL_OFFSET_TABLE_, %eax
movl 8(%ebp), %eax
addl 03, %eax
popl %ebp
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE0:
.size g, .-g
.globl f
.type f, @function
f:
.LFB1:
.cfi_startproc
endbr32
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
call __x86.get_pc_thunk.ax
addl $_GLOBAL_OFFSET_TABLE_, %eax
pushl 8(%ebp)
call g
addl , %esp
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE1:
.size f, .-f
.globl main
.type main, @function
main:
.LFB2:
.cfi_startproc
endbr32
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
call __x86.get_pc_thunk.ax
addl $_GLOBAL_OFFSET_TABLE_, %eax
pushl
call f
addl , %esp
addl , %eax
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE2:
.size main, .-main
.section .text.__x86.get_pc_thunk.ax,"axG",@progbits,__x86.get_pc_thunk.ax,comdat
.globl __x86.get_pc_thunk.ax
.hidden __x86.get_pc_thunk.ax
.type __x86.get_pc_thunk.ax, @function
__x86.get_pc_thunk.ax:
.LFB3:
.cfi_startproc
movl (%esp), %eax
ret
.cfi_endproc
.LFE3:
.ident "GCC: (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0"
.section .note.GNU-stack,"",@progbits
.section .note.gnu.property,"a"
.align 4
.long 1f - 0f
.long 4f - 1f
.long 5
0:
.string "GNU"
1:
.align 4
.long 0xc0000002
.long 3f - 2f
2:
.long 0x3
3:
.align 4
4:
在vim编辑器中,输入命令g/\.s*/d
,删除所有以.
打头的字符串,“美化”得到的汇编代码,如下所示:
g:
endbr32
pushl %ebp
movl %esp, %ebp
addl $_GLOBAL_OFFSET_TABLE_, %eax
movl 8(%ebp), %eax
addl 03, %eax
popl %ebp
ret
f:
endbr32
pushl %ebp
movl %esp, %ebp
addl $_GLOBAL_OFFSET_TABLE_, %eax
pushl 8(%ebp)
call g
addl , %esp
leave
ret
main:
endbr32
pushl %ebp
movl %esp, %ebp
addl $_GLOBAL_OFFSET_TABLE_, %eax
pushl
call f
addl , %esp
addl , %eax
leave
ret
movl (%esp), %eax
ret
二、汇编语言分析
main函数
代码片段 | 含义 |
---|---|
pushl %ebp | 将EBP寄存器的值也即栈底指针压栈 |
movl %esp, %ebp | 将ESP寄存器的值也即栈顶指针存入EBP寄存器 |
pushl | 将28压栈 |
call f | 调用f 函数 |
addl , %esp | ESP寄存器的值加4,指向调用f函数前的栈顶 |
addl , %eax | EAX寄存器的值加3,即2831+3=2834 |
leave | 撤销函数堆栈 |
ret | 返回更上层的堆栈 |
代码片段 | 含义 |
---|---|
pushl %ebp | 将EBP寄存器的值也即栈底指针压栈 |
movl %esp, %ebp | 将ESP寄存器的值也即栈顶指针存入EBP寄存器 |
pushl 8(%ebp) | 将EBP寄存器的值加8,指向之前压入栈的数28,然后将28压栈 |
call g | 调用g 函数 |
addl , %esp | ESP寄存器的值加4,指向调用g函数前的栈顶 |
leave | 撤销调用函数的堆栈 |
ret | 回退到f 函数调用的代码处 |
代码片段 | 含义 |
---|---|
pushl %ebp | 将EBP寄存器的值也即栈底指针压栈 |
movl %esp, %ebp | 将ESP寄存器的值也即栈顶指针存入EBP寄存器 |
movl 8(%ebp), %eax | 将EBP寄存器的值加8,指向之前压入栈的数28,将28存入EAX寄存器 |
addl 03, %eax | EAX寄存器的值加2803,即28+2803=2831 |
popl %ebp | 将栈顶数据存入EBP寄存器,也即调用g函数前的栈顶指针 |
ret | 回退到g 函数调用的代码处 |
以上具体过程参考了完整汇编程序执行过程分析
遇到的问题一、在虚拟机中反汇编失败,报错如图:
解决方法:是由于在64位系统上编译32位可执行程序缺少相应的32位库文件所致,在终端输入sudo apt-get install gcc-multilib
之后解决。解决方法来自于“/usr/include/stdio.h:27:10: fatal error: bits/libc-header-start.h: No such file or directory 报错解决”
二、对pushl 8(%ebp)
的理解错误
解决方法:仔细查阅《庖丁解牛Linux 分析 》第25页内容得到解决。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)