linux c语言反汇编分析,通过反汇编一个简单的C程序,分析汇编代码理解计算机是如何工作...

刘子健原创作品转载请注明出处《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000对一下代码进行反汇编分析:int g(int x){ return x +

刘子健

原创作品转载请注明出处

《Linux内核分析》MOOC课程

对一下代码进行反汇编分析:

int g(int x)

{

return x + 42;

}

int f(int x)

{

return g(x);

}

int main(void)

{

return f(42) + 42;

}

我的主机是64位的Linux,所以使用的反汇编代码也是64-bits的.

.file"2015_03_01.c"

.text

.globlg

.typeg, @function

g:

.LFB0:

.cfi_startproc

pushq%rbp

.cfi_def_cfa_offset 16

.cfi_offset 6, -16

movq%rsp, %rbp

.cfi_def_cfa_register 6

movl%edi, -4(%rbp)

movl-4(%rbp), %eax

addl$42, %eax

popq%rbp

.cfi_def_cfa 7, 8

ret

.cfi_endproc

.LFE0:

.sizeg, .-g

.globlf

.typef, @function

f:

.LFB1:

.cfi_startproc

pushq%rbp

.cfi_def_cfa_offset 16

.cfi_offset 6, -16

movq%rsp, %rbp

.cfi_def_cfa_register 6

subq$8, %rsp

movl%edi, -4(%rbp)

movl-4(%rbp), %eax

movl%eax, %edi

callg

leave

.cfi_def_cfa 7, 8

ret

.cfi_endproc

.LFE1:

.sizef, .-f

.globlmain

.typemain, @function

main:

.LFB2:

.cfi_startproc

pushq%rbp

.cfi_def_cfa_offset 16

.cfi_offset 6, -16

movq%rsp, %rbp

.cfi_def_cfa_register 6

movl$42, %edi

callf

addl$42, %eax

popq%rbp

.cfi_def_cfa 7, 8

ret

.cfi_endproc

.LFE2:

.sizemain, .-main

.ident"GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"

反汇编得到的代码里面有很多提示信息,提示信息以 . 开头,程序执行时这些提示信息不是指令,我们在这个反汇编样例里面可以精简代码,把这些提示信息删除.有些信息不能剔除,这些信息是编译器必须的,否则你过不了编译链接.

下面是精简后的反汇编代码:以下代码可以通过 gcc ./2015_03_01.s -o ./a.out

.text

.globlg

.typeg, @function

g:

pushq%rbp

movq%rsp, %rbp

movl%edi, -4(%rbp)

movl-4(%rbp), %eax

addl$42, %eax

popq%rbp

ret

.sizeg, .-g

.globlf

.typef, @function

f:

pushq%rbp

movq%rsp, %rbp

subq$8, %rsp

movl%edi, -4(%rbp)

movl-4(%rbp), %eax

movl%eax, %edi

callg

leave

ret

.sizef, .-f

.globlmain

.typemain, @function

main:

pushq%rbp

movq%rsp, %rbp

movl$42, %edi

callf

addl$42, %eax

popq%rbp

ret

.sizemain, .-main

关于基本汇编指令的分析,我之前有笔记,可以去看这里:

我们这里着重分析反汇编代码:

g: , f:, main: 均用来指示函数的入口.

对于函数main.

首先压栈,pushq 指令将rsp寄存器的值减去一个指针长度,在64-bits机器上即8byte,然后将 rbp寄存器的值写入到rsp指向的地址处.

movq %rsp, %ebp指令则将rsp寄存器的值赋值给rbp寄存器.这样一来,属于main函数的栈区域便构建好了.

接着movl 把立即数42赋值给寄存器edi, 然后call指令调用函数f.函数f的返回值会储存在eax寄存器中,等待f调用完之后,会把eax寄存器的值和立即数42相加,并储存在eax寄存器中.最后把rbp寄存器处的值弹栈.然后ret指令返回.

call  f

指令就相当于

push %eip #把当前指令指针寄存器压栈,然后跳转到f处

jump f

---------------------------------------------------------------------------------

ret

指令就相当于

popl %eip  #把当前esp寄存器指向地址处的值,赋值给eip

然后把esp寄存器的值减去一个指针长度,即8-byte

ad7fe11308a90eab6e0cfeb941eee874.png

看看函数f都干了神马.

还是和上面介绍main函数一样的"老规矩",构建函数f的堆栈,

pushq %rbp

movq %rsp, %rbp

接着使用subq $8, %rsp把rsp寄存器的值减去8.

接着把edi寄存器的值赋值给rbp寄存器指向地址处减去4byte的地址处

紧接着,,把这个地址处的值赋值给eax寄存器.

把eax寄存器的值又赋值给edi寄存器(其实我想说,这不是吓折腾么...这编译器啊..这期间edi寄存器的值没变)

97a64d935f80ab34ab80db9eb251034e.png

然后调用函数g

一句话概括就是把edi寄存器的值加上42赋值给eax寄存器,然后返回.(不改变edi寄存器的值)

bad35224c273ef67de12e9b1ceef1c0e.png

阐明自己对“计算机是如何工作的”理解:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值