c语言其二

news/2024/11/15 15:33:10/文章来源:https://www.cnblogs.com/yuli10952/p/18315811

1.代码区:可读可执行

2.堆栈:(参数,局部变量,临时数据)

3.堆:(动态申请,大小可变)可读可写

5.常量区:只读

变量

变量的声明

全局变量

int a,b,c; //全局变量的声明   

void Fun()   

{   

 a = 10; //全局变量的赋值  

 b = 20;  

 c = a;  

}

局部变量

void Fun()   

{   

 int a,b,c; //局部变量的声明  

 a = 10; //局部变量的赋值  

 b = 20;  

 c = a;  

}      

全局变量

特点:           

1、在程序编译完以后就已经预留的空间,预留的大小由类型决定,且位置不会发生变化.           

2、全局变量如果没有给的初始值,默认为0.         

3、全局变量可以在任何其他的函数里面进行读写

如图:

       

等于:MOV 寄存器,byte/word/dword ptr ds:[0x12345678]

4、多个函数使用同一个全局变量,只要exe程序不结束,里面将一直存储最后一次修改的值.        

注:全局变量就是所谓的基址

局部变量

局部变量的特点:            

1、局部变量在程序编译完成后并没有分配固定的地址.               

2、在所属的方法没有被调用时,局部变量并不会分配内存地址,只有当所属的程序被调用了,才会在

 堆栈中分配内存.             

3、当局部变量所属的方法执行完毕后,局部变量所占用的内存将变成垃圾数据.局部变量消失.              

4、局部变量只能在方法内部使用,函数A无法使用函数B的局部变量.           

5、局部变量的反汇编识别:   [ebp-4].....

6.使用前要赋初值

参数

传进来给函数里用

确定参数

一般情况

步骤一:观察调用处的代码     

push 3   

push 2   

push 1   

call 0040100f       //3个参数

步骤二:找到平衡堆栈的代码继续论证    

call 0040100f   

add esp,0Ch     

或者函数内部    

ret 4/8/0xC/0x10         //1/2/3/4个参数

寄存器传参

举例


 

1.

push ebx   

push eax   

mov ecx,dword ptr ds:[esi]   

mov edx,dword ptr ds:[edi]   

push 45   

push 33   

call 函数地址   函数地址未知 

2、函数调用处的代码无法查看.   

00401050 push ebp   

00401051 mov ebp,esp   

00401053 sub esp,48h   

00401056 push ebx   

00401057 push esi   

00401058 push edi   

00401059 push ecx   

0040105A lea edi,[ebp-48h]   

0040105D mov ecx,12h            将12h赋给ecx(不属于参数

00401062 mov eax,0CCCCCCCCh   

00401067 rep stos dword ptr [edi]   

00401069 pop ecx   

0040106A mov dword ptr [ebp-8],edx     将edx里的值赋给[ebp-8]中(发现前面没有给edx赋值,所以edx存了一个参数

0040106D mov dword ptr [ebp-4],ecx   

00401070 mov eax,dword ptr [ebp-4]   

00401073 add eax,dword ptr [ebp-8]   

00401076 add eax,dword ptr [ebp+8]   

00401079 mov [g_x (00427958)],eax   

0040107E pop edi   

0040107F pop esi   

00401080 pop ebx   

00401081 mov esp,ebp   

00401083 pop ebp   

00401084 ret 4   有一个压栈的参数

 


2.if汇编

00401030 push ebp    

00401031 mov ebp,esp    

00401033 sub esp,40h    

00401036 push ebx    

00401037 push esi    

00401038 push edi    

00401039 lea edi,[ebp-40h]    

0040103C mov ecx,10h    

00401041 mov eax,0CCCCCCCCh    

00401046 rep stos dword ptr [edi]    

——————————————————————————————————————堆栈图准备部分

00401048 mov eax,dword ptr [ebp+8]    参数x

0040104B cmp eax,dword ptr [ebp+0Ch]       参数y

0040104E jle 00401059    ≤跳转不执行

00401050 mov ecx,dword ptr [ebp+8]    x的值赋值给ecx

00401053 mov dword ptr [004225c4],ecx    全局变量(宽度4个字节)ecx赋值给全局变量

——————————————————————————————————————————平衡堆栈

00401059 pop edi    

0040105A pop esi    

0040105B pop ebx    

0040105C mov esp,ebp    

0040105E pop ebp    

0040105F ret    

 

 


 

公式:

1、不考虑ebp、esp    

2、只找给别人赋值的寄存器    

eax/ecx/edx/ebx/esi/edi       

3、找到以后追查其来源,如果,该寄存器中的值    

不是在函数内存赋值的,那一定是传进来的参数.      

公式一:寄存器 + ret 4 = 参数个数    

公式二:寄存器 + [ebp+8] +[ebp+0x] = 参数个数    

循环

if与else

1.if....else

int x=1;

int y=2

void one()

{

      if(x>y)   //如果

       {

       printf("%d\n",x);

         }

       else     //否则

       {

       printf("%d\n",y);

         }

}

2.else if

3.嵌套

汇编(if

1.

 

cmp:eax里的值减去[ebp+0Ch],根据结果后只修改标志寄存器

jle:当eax里的值<或者=[ebp+0Ch]的时候跳转(不执行if里的代码

2.

jl:小于才跳转

jge:≥

( else

 

004010B0 push ebp    

004010B1 mov ebp,esp    

004010B3 sub esp,44h    

004010B6 push ebx    

004010B7 push esi    

004010B8 push edi    

004010B9 lea edi,[ebp-44h]    

004010BC mov ecx,11h    

004010C1 mov eax,0CCCCCCCCh    

004010C6 rep stos dword ptr [edi]    

———————————————————————————————————————————————————————

004010C8 mov eax,[004225c4]    全局变量

004010CD mov dword ptr [ebp-4],eax   局部变量(将全局变量赋值给局部变量)

004010D0 mov ecx,dword ptr [ebp+8]    参数x

004010D3 cmp ecx,dword ptr [ebp+0Ch]    参数y

004010D6 jle 004010e6   ≤跳转,不执行

—————————————————————————————————————————————

004010D8 mov edx,dword ptr [ebp+8]    

004010DB add edx,dword ptr [ebp-4]    x+全局变量

004010DE mov dword ptr [004225c4],edx    

004010E4 jmp 004010f1   

int a=r;

if(x>y)

{

r=x+a;

}—————————————————————————————————————————    

004010E6 mov eax,dword ptr [ebp+0Ch]    

004010E9 add eax,dword ptr [ebp-4]    

004010EC mov [004225c4],eax    

————————————————————————————————————————————————

004010F1 pop edi    

004010F2 pop esi    

004010F3 pop ebx    

004010F4 mov esp,ebp    

004010F6 pop ebp    

004010F7 ret    

do....while

格式

do..while语句的语法 

 

do 

 //执行代码

 

}while(表达式) 

例子

void Fun(int x,int y)   

{   

 do  

 {  

  printf("%d\n",x); 

  x++; 

 }while(x>y);  

}   

汇编

0040B7F8 mov eax,dword ptr [ebp+8]      

0040B7FB push eax      

0040B7FC push offset string "%d\n" (0042001c)      

0040B801 call printf (004010f0)      

0040B806 add esp,8      

0040B809 mov ecx,dword ptr [ebp+8]      //x++

0040B80C add ecx,1                                 //

0040B80F mov dword ptr [ebp+8],ecx      //while(x>y)

0040B812 mov edx,dword ptr [ebp+8]      //

0040B815 cmp edx,dword ptr [ebp+0Ch]      //

0040B818 jg 0040b7f8      

总结

1、根据条件跳转指令所跳转到的地址,可以得到循环语句块的起始地址。     

2、根据条件跳转指令所在的地址,可以得到循环语句块的结束地址。     

3、条件跳转的逻辑与源码相同。

while

语法  

while(表达式)  

{  

 //执行代码 

}  

例子

void Fun(int x,int y)   

{   

 while(x<y)  

 {  

  printf("%d\n",x); 

  x++; 

 }  

}   

汇编

0040B7F8 mov eax,dword ptr [ebp+8]    

0040B7FB cmp eax,dword ptr [ebp+0Ch]    

0040B7FE jge 0040b81c    //

0040B800 mov ecx,dword ptr [ebp+8]    //

0040B803 push ecx                                //

0040B804 push offset string "%d\n" (0042001c)   // 

0040B809 call printf (004010f0)    //

0040B80E add esp,8    //

0040B811 mov edx,dword ptr [ebp+8]    //

0040B814 add edx,1    //

0040B817 mov dword ptr [ebp+8],edx    //

0040B81A jmp 0040b7f8    //

0040B81C pop edi    //

0040B81D pop esi    //

0040B81E pop ebx    //

总结:           

1、根据条件跳转指令所跳转到的地址,可以得到循环语句块的结束地址;      

2、根据jmp 指令所跳转到的地址,可以得到循环语句块的起始地址;      

for(表达式1;表达式2;表达式3)

for循环的执行次序:  

表达式1  

表达式2  

执行的代码(大括号里面的内容)  

表达式3  

————————————————

表达式2 //如果表达式2成立  

执行的代码(大括号里面的内容)  

表达式3  

————————————————

表达式2 //如果表达式2成立  

执行的代码(大括号里面的内容)  

表达式3  

———————————————

表达式2 //如果不成立  

跳出循环  

汇编

0040B7F8 mov eax,dword ptr [ebp+8]    //i=x

0040B7FB mov dword ptr [ebp-4],eax    //

0040B7FE jmp 0040b809    //

0040B800 mov ecx,dword ptr [ebp-4]    //

0040B803 add ecx,1    //

0040B806 mov dword ptr [ebp-4],ecx    //

0040B809 mov edx,dword ptr [ebp-4]    //

0040B80C cmp edx,dword ptr [ebp+0Ch]    //

0040B80F jge 0040b824    //

0040B811 mov eax,dword ptr [ebp-4]    //

0040B814 push eax    //

0040B815 push offset string "%d\n" (0042001c)    //

0040B81A call 004010f0    //

0040B81F add esp,8    //

0040B822 jmp 0040b800    //

0040B824 pop edi    //

0040B825 pop esi    //

0040B826 pop ebx    //

总结:

1、第一个jmp 指令之前为赋初值部分.  

2、第一个jmp 指令所跳转的地址为循环条件判定部分起始.  

3、判断条件后面的跳转指令条件成立时跳转的循环体外面   

4、条件判断跳转指令所指向的地址上面有一个jmp jmp地址为表达式3的起始位置    

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/773647.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[米联客-安路飞龙DR1-FPSOC] FPGA基础篇连载-15 SPI接收程序设计

软件版本:Anlogic -TD5.9.1-DR1_ES1.1 操作系统:WIN10 64bit 硬件平台:适用安路(Anlogic)FPGA 实验平台:米联客-MLK-L1-CZ06-DR1M90G开发板 板卡获取平台:https://milianke.tmall.com/ 登录"米联客"FPGA社区 http://www.uisrc.com 视频课程、答疑解惑! 1概述SP…

自写Json转换工具

前面写了简单的API测试工具ApiTools,返回的json有时需要做很多转换,于是开发了这个工具。 功能包括 1、json字符串转为表格,可以直观的展示,也可以复制,并支持转换后的表格点击列头进行排序,比较方便地定位数据。2、表格转为EXCEL,就是导出Excel文件,支持2003和2007格式…

[米联客-安路飞龙DR1-FPSOC] FPGA基础篇连载-13 SPI通信协议原理

SPI(串行外围设备接口)通信协议是一种高速、全双工、同步通信总线。它通过四根管脚实现控制和数据传输,广泛应用于EEPROM、Flash、RTC、ADC、DSP等设备,是一种重要的低速通讯协议。SPI协议具有高速、全双工、同步、主从式等特点,接口速度最高可达上百兆,因此不仅适用于低…

DiffSeq

目录概 符号说明 流程 代码 Gong S., Li M., Feng J., Wu Z. and Kong L. DiffuSeq: Sequence to sequence text generation with diffusion models. In International Conference on Learning Representations (ICLR), 2023概 本文提出了一种用于 Seq2Seq 的不需要 classifier…

嵌入式测试手册——基于NXP iMX6ULL开发板(2)

基于测试板卡:创龙科技TLIMX6U-EVM是一款基于NXP i.MX 6ULL的ARM Cortex-A7高性能低功耗处理器设计的评估板,由核心板和评估底板组成。核心板经过专业的PCB Layout和高低温测试验证,稳定可靠,可满足各种工业应用环境。评估板接口资源丰富,引出双路网口、双路RS485、双路CA…

广东注塑行业MES系统——优化生产管理的利器

注塑行业MES系统是优化生产管理的利器,具有以下优势和作用: 实现生产过程的数字化管理:注塑行业MES系统可以实现生产过程的数字化管理,实时监控生产数据、设备状态和生产进度,提高生产过程的可视化和透明度。提高生产效率:通过优化生产计划、资源调度和工艺流程,注塑MES…

嵌入式基础测试手册——基于NXP iMX6ULL开发板(4)

前 言 本文档适用开发环境: Windows开发环境:Windows 7 64bit、Windows 10 64bit 虚拟机:VMware15.1.0 Linux开发环境:Ubuntu18.04.4 64bit U-Boot:U-Boot-2020.04 Kernel:Linux-5.4.70 Linux SDK:5.4.70_2.3.0 基于测试板卡:创龙科技TLIMX6U-EVM是一款基于NXP i.MX 6…

Markdown 常用语法

上一篇简单介绍了 Markdown 是什么,以及如何使用,本篇就来详细说说 Markdown 的常见语法。上一篇简单介绍了 Markdown 是什么,以及如何使用,本篇就来详细说说 Markdown 的常见语法。 ‍ 注意,并不是所有编辑器,都支持所有的 Markdown 语法,如果遇到失效的也不必疑惑。 此…

软件无线电系统基带信号处理卡:612-基于6UVPX C6678+XCVU9P的4路2Gsps AD 8路2Gsps DA 信号处理板卡

基于6UVPX C6678+XCVU9P的4路2Gsps AD 8路2Gsps DA 信号处理板卡 一、板卡概述板卡基于6U VPX标准结构,包含一个C6678 DSP芯片,一个XCVU9P 高性能FPGA,8路DA ,4路AD。 二、技术指标● DSP处理器采用TI 8核处理器TMS320C6678; ● DSP 外挂一组64bit DDR3颗粒,总容量2G…

AM62x相比AM335x,到底升级了什么?

Sitara作为TI处理器经典系列,曾推出众多优秀处理器型号(如AM335x)。因其能在相同价位下,提供比市面上其他厂商处理器更优良的性能,并凭借GPMC高速并口、PRU协处理器等个性化硬件资源,可提供更便利的拓展性,在工业控制、能源电力、轨道交通、智慧医疗等领域广受用户欢迎。…

NXP IMX8M Plus工业核心板规格书

核心板简介 创龙科技SOM-TLIMX8MP是一款基于NXP i.MX 8M Plus的四核ARM Cortex-A53 + 单核ARM Cortex-M7异构多核处理器设计的高端工业核心板,ARM Cortex-A53(64-bit)主处理单元主频高达1.6GHz,ARM Cortex-M7实时处理单元主频高达800MHz。 处理器采用14nm最新工艺,内置2.3TO…