用汇编来看C语言的简单实现(转)

本文深入探讨了C语言与汇编语言之间的区别,并通过一个简单的C语言程序实例展示了其在汇编语言层面的具体实现。详细解释了堆栈操作、数据传送指令、跳转与比较指令、循环指令等关键概念,同时提供了实例代码的反汇编结果,清晰地展示了汇编语言如何实现这些功能。通过对比和实例解析,旨在帮助开发者理解不同编程语言底层的差异与实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

好久没更新日志了,一是学习的时间实在有限.二是多是走马观花的看书.今天闲下来,写篇技术文章吧.反正无聊.
先来复习几个相关的ASM指令.

1.堆栈相关指令

push : 把一个32位的操作数压入堆栈中.(操作导致esp被减4)

pop : 相反,esp加4,一个数据出栈.

sub : 减法.第一个参数是被减数所在的寄存器;第二个参数是减数(对应的还有add指令)

add : 加法.

ret :返回.(相当于跳转回调用函数的地方)

call : 调用函数(ret跳转到call的下一条指令)

2.数据传送指令

mov : 数据移动.第一个参数是目的,第二个参数是来源.(C语言中相当于赋值运算符)

xor : 异或.

lea : 取得地址(第二个参数)后放入到前面的寄存器(第一个参数)中.

比如 : lea edi ,[ebp - 0cch] ([]括号表示存储器,ebp-0cch这个地址所指的存储器内容)

把ebp-0cch放入edi中.等同于 mov edi ebp-0cch但这样的方法是错的.

我们知道,mov不支持后一个数写成寄存器减去个数,但是lea支持.

3.跳转与比较指令

jmp : 无条件跳转.

jp : 大于的时候跳转

jl : 小于的时候跳转

jge : 大于等于的时候跳转

cmp : 比较 .是 jg jl jge 之类的条件跳转指令的执行条件.

4.循环指令

rep指令的目的是重复其上面的指令. ECX的值是重复的次数.
STOS指令的作用是将eax中的值拷贝到ES:EDI指向的地址. 如果设置了direction flag, 那么edi会在该指令执行后减小, 如果没有设置direction flag, 那么edi的值会增加, 这是为了下一次的存储做准备.
REP可以是任何字符传指令(CMPS, LODS, MOVS, SCAS, STOS)的前缀. REP能够引发其后的字符串指令被重复, 只要ecx的值不为0, 重复就会继续. 每一次字符串指令执行后, ecx的值都会减小.


.进入实例

// windows编程.cpp : 定义控制台应用程序的入口点。

//

#include "stdafx.h"


int _tmain(int argc, _TCHAR* argv[])

{

return 0;

}

void myfunction(int a,int b)

{

int c = a + b;

}

(本人用的是 VS2008 测试.)

在 return 0 处.

int c = a + b 处 设置2个断点.

然后进入调试,窗口,反汇编.得到以下代码:


#include "stdafx.h"


int _tmain(int argc, _TCHAR* argv[])

{

00CF1370 push ebp

00CF1371 mov ebp,esp ;把esp,移动至 ebp地址

00CF1373 sub esp,0C0h

00CF1379 push ebx ;保存3个寄存器 :ebx,esi,edi

00CF137A push esi

00CF137B push edi

00CF137C lea edi,[ebp-0C0h];把ebp-0c0h地址内容移动到edi中

00CF1382 mov ecx,30h

00CF1387 mov eax,0CCCCCCCCh ;0cccccccch c语言初始化地址(其实是 int 3 中断的机器码)

00CF138C rep stos dword ptr es:[edi] ;串写入

return 0;

00CF138E xor eax,eax

}

00CF1390 pop edi 恢复 3个寄存器 edi,esi,ebx

00CF1391 pop esi

00CF1392 pop ebx

00CF1393 mov esp,ebp

00CF1395 pop ebp

00CF1396 ret



void myfunction(int a,int b)

{

00CF14A0 push ebp ;保存ebp,并把esp放入ebp中.此时ebp与esp

00CF14A1 mov ebp,esp ;同都是这次函数调用的栈顶.

00CF14A3 sub esp,0CCh 把esp往上移动一个范围,等于在堆栈中放出一片新的空间用来存储局部变量

00CF14A9 push ebx ;保存3个寄存器

00CF14AA push esi

00CF14AB push edi

00CF14AC lea edi,[ebp-0CCh]

00CF14B2 mov ecx,33h

00CF14B7 mov eax,0CCCCCCCCh

00CF14BC rep stos dword ptr es:[edi]

int c = a + b;

00CF14BE mov eax,dword ptr [a] ;把a的值放入eax这个寄存器中(把a压入堆栈)

00CF14C1 add eax,dword ptr ;把b的值加到eax这个寄存器中(把b压入堆栈)

00CF14C4 mov dword ptr [c],eax ;把寄存器中a + b的值移动至c.

}

00CF14C7 pop edi

00CF14C8 pop esi

00CF14C9 pop ebx

00CF14CA mov esp,ebp

00CF14CC pop ebp

00CF14CD ret


现在,我大体的写出C语言循环的汇编指令

(循环变量,常量均用16进制表示)

for 循环

mov <循环变量>,<初始值> ;给循环变量赋初值

jmp B(地址) ;跳到第一次循环处

A:(改动循环变量) ;修改循环变量

.....

B:cmp<循环变量>,<限制变量> ;检查循环条件

jpe 跳出循环

(循环体)

...

jmp A ; 跳回去修改循环变量

while 循环

A: cmp<循环变量>,<限制变量>

jpe B

(循环体)

....

jmp A

B:(循环结束)


这就实现了汇编语言相应和C语言之间的一些简单关系.

好了.累死了..下次继续吧.洗了睡了

相比C来说,汇编确实高效且快速.

从以上的一个小程序的测试,我们可以看到.汇编对每个地址的操作.相比于纯粹的C语言.汇编更可能接触到计算机底层.

我的建议是,多点旁内触及,这才是王道..

转自:http://www.pediy.com/kssd/pediy11/117424.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值