当前位置: 首页 > news >正文

个人网站备案 淘宝客南京做网站建设搭建的公司

个人网站备案 淘宝客,南京做网站建设搭建的公司,专注营销型网站建设,wordpress仿seowhy基础指南模板文章目录 一#xff0c;什么是寄存器 二#xff0c;栈和帧 前言 我们在学习c语言程序的时候#xff0c;是不是有很多的疑问#xff0c;如 1#xff0c;为什么形参不可以改变实参 2#xff0c;为什么我们编写程序的时候会出现烫烫烫......这个乱码 3#xff0c;那些局…  文章目录 一什么是寄存器 二栈和帧 前言 我们在学习c语言程序的时候是不是有很多的疑问如 1为什么形参不可以改变实参 2为什么我们编写程序的时候会出现烫烫烫......这个乱码 3那些局部变量和全局变量为什么是全局变量先在程序中出现局部变量在后面出现 4为什么会出现栈溢出错误栈的大小是怎么弄出来的 5为什么文件的查找数据需要用流但是printf和scanf也是寻找数据为什么不用设置流难道提前设置好了 等等一系列的问题接下来我们就要来学习函数栈帧来知道这些问题 一.什么是寄存器 具有存储功能的硬件 在计算机中具有的存储功能的硬件有哪些呢 硬盘 -- 内存 -- 高速缓存 -- 寄存器 (从左到右) 访问的速度和缓存的速度是在增加的 容量的大小是在减少的 价格的大小是在增加的 如果我们考虑外部的存储的话就是这样的 磁带光盘 -- 硬盘 -- 内存 -- 高速缓存 -- 寄存器规律和上面的是一样的 这里我们生活中所用的u盘其实就是硬盘只不过把他取出来了 寄存器 存储的空间只有4Byte为的存储空间这里说的是32位寄存器因为很广泛访问速度也是最快的 那为什么寄存器的访问速度是最快的呢 因为寄存器是集成在cpu上面的与内存不同它是一个独立的空间 寄存器的分类 (寄存器中的E其实是extend的英文缩写表示把16位寄存器扩展到32位寄存器没有带E的就是16位寄存器带E的就是32位前面这种在x86框架情况是对的在其他框架不适用如在x86-64架构也称为AMD64中寄存器被扩展到64位如RAX, RBX, RCX, RDX等这些寄存器可以访问其32位和16位部分我们要考虑框架和文件) 一般的寄存器EAX  EBX  ECX  EDX   ax累积暂存器    bx基底暂存器  cx计数暂存器    dx资料暂存器 索引寄存器ESI   EDI si来源索引暂存器   di目的暂存器 堆叠基底寄存器ESP   EBP sp堆叠指标暂存器  dp基底指标暂存器 寄存器的用途 每个寄存器都是有自己各自的专长与特别之处 一般寄存器 1.EAXAaccumulation 积累  /   accumulate 计算 1为“累加器”进行加法减法乘法除法运算时被当做累加器使用体现出加法的原理 为整数与浮点数计算的核心寄存器之一 2用于保存计算的结果和数据 2.EBX Bbase 基本 1用于保存基地址的信息常用于访问内存的数据与元素 2用于保存指针和地址信息方便与其他的内存地址进行运算 3.ECXCcounter  计数  1通常被用为计数器放到循环与迭代操作在循环里面ECX是可以用于保存循环次数的然后自己递减直到0就停止 4.EDXDdata  数据 1保存数据和计算结果的临时存储 2用于存储整数除法的余数 总结一下一般寄存器 A是计算所以是作为四则运算的寄存器累加器还有一个额外的功能存储数据和结果 B是基本所以是保存基地址用于访问里面的数据与元素因为存的是地址所以就很方便利用地址运算 C是计数所以一般存储循环的条件值然后自己会自己递减到0然后进行结束 D是数据这里就是存储数据的所以可以存储数据和计算结果还有整数的乘法和除法的余数 索引暂存器 1.ESISsource 源头 1这里主要存储指向源数据的指针和索引它经常与字符串一起使用指示要操作的字符串的首地址 这里的“源数据”指的是在执行某些指令时需要从中读取数据的内存位置或数据结构 2.EDIDdestination目的地 1这里存储目标数据的指针和索引通常指向目标字符串的起始位置以指示存储的位置 总结一下索引寄存器 ESIs 源头这里是存储指向源数据的开头以便于可以方便操作这个数据 EDId 目标这里是存储目标数据的开头方便提示这个存储这个目标数据的位置 堆叠基底暂存器 1.EBPB  基底 1存储堆栈帧的基地址的指针很重要 2在函数调用的和返回的过程中主要用于维护栈帧的上下文的数据信息以便正常访问局部变量传递参数和保存返回地址 2.ESPS stack 栈顶 1存储堆栈帧的栈顶的指针很重要 2在函数调用的和返回的过程中主要用于管理栈帧的内存当压入栈的数据越多ESP也会相对移动可以理解为减少 3.EIPI  instruction 1存储下一条需要进行的指令cpu根据EIP来跟踪程序执行的流程执行完自动更新EIP指向下一个指令 总结一下堆叠基底暂存器 EBPB 基底主要储存基底的地址所以可以很好管理这些数据 ESPS 栈顶主要储存栈顶的地址所以可以根据栈顶指针的移动来管理栈的内存 EIP I(交互)主要是存储下一个指令方便后续的程序的进行可以理解为是为了进行交互 二栈和帧 1栈是什么呢 数据依次存入栈中去元素的时候最先放入的元素最后拿出来最后放入的元素最先拿出来这个就是栈 可以理解为现实生活中的放东西与取东西 2函数栈帧的概念 在计算机科学中有这么一个概念它是指在调用函数的时候系统为函数调用创建一块内存区域这块内存区域存储了函数的局部变量函数的参数返回地址等信息 这个时候ESP和EBP是会去维护这个函数的空间在函数运行的时候ESP栈顶指针指向栈的头部EBP指向栈的底部假设我们整一个main函数 这个就是我们运行到main函数的时候所形成的栈帧 3main函数的压栈过程 在运行调试程序的过程中我们可以调用堆栈时发现main函数其实也是被别的函数调用的 分别是_tmainCRTStartup和mainStarup函数调用的逻辑顺序为 mainStatrup  --  _tmainCRTStartup  --  main 这个是mainStartup压栈 这个是_tmainCRTStartup压栈 mainStarup函数非Unicode版本的例程它负责main函数的初始化 _tmainCRTStartup函数Unicode版本的例程他也是负责main函数的初始化但是它是支持Unicode字符的初始化 Unicode的大概理解把我们的文字组合起来让计算机认识并表示出来 初始化1环境的设置全局变量的初始化等...   2命令行参数的解析  3I/O流的初始化这个时候我们才可以用到这个printf和scanf的函数输入输出4信号处理  5其他系统的初始化 这个可以理解很多问题了函数的压栈就是这样 三样例程序的压栈  #includestdio.h int add(int x,int y) {int z 0;z x y;return z; } int main() {int a 10;int b 10;int c 0;cadd(a, b);printf(%d, c);return 0; } 1main函数的构造 以汇编语言讲述  常见的汇编语言这个是截取一个学长的图片 这个是我们main函数前面还没有调用add函数时候的汇编语言  第一步 push的作用是把这个东西压入栈中 这里的意思是把ebp这三个压入栈中 图示有两种情况会是那种呢这里的那个ebp下面的空间是_tmainCRTStartup的 由于2019的vs不可以监视到edp的改变我们可以通过这个来看来判断是左图还是右图 我们来监视esp的值是多少  然后打开内存块区寻找ebp的地址记住这里的ebp不是ebp栈底指针而是压入到栈的寄存器一定不要搞混了我们去内存块区寻找一下这个ebp的地址 这里看到地址为0x0137FA34   我们把这个20445748十进制转换一下换成十六进制看看是否相同 由于大小端的问题所以这个是倒着存的如果想知道为什么倒着存储可以去了解一下大小端这里我们可以观察到这个esp栈顶指针指向的地址就是ebp上面右图是对的所以我们每当我们压入栈数据的时候这个esp是实时进行变换的 第二步 mov的作用是把后者赋值给前者 所以这里的作用是把esp的地址赋给ebp那这里的图是什么样的呢 第三步  sub的英文的意思是减去的意思前者减去后者这么多 注我们下面是高地址上面为低地址 在这里是向上增长0E4h228这么多的空间这里的h是十六进制的后缀  由于vs2019无法观察这个过程所以建议读者可以去寻找vs2013去学习这样可以更加直观所以这里就是在创建一个空间  第四步  这里的ebxesiedi都是非易失寄存器什么事非易失寄存器呢就是在电源关闭的时候也可可以保存其中的内容那么我们怎么画这个时候的图呢要记得我们在操作的时候这个esp栈顶指针是会改变的 这个操作就是把这几个寄存器压入栈里面去 第五步 lea全名是lead effective address加载有效地址 从此处正式加载当前函数的有效栈区域 这里是把ebp-24h这个地址存放在edi里面(我们来回顾一下edi在下面这个是存储一个这个这么大的空间的指针为了准备一个内存区域用于存储函数的局部变量等的数据有了这个edi才可以找到这个地方的首地址才可以确保数据的正常存储 注因为这个vs2019这个是根据你写的代码所写的汇编语言每个编译器都是不一样的如果你在main函数里面不断写入变量这个就是会改变的其实VS2013真正的写的是[ebp-0E4h]的 栈开辟之后是不可以改变的如果超出了栈就会报栈溢出错误一般来说都是200多M的大小一个函数这里的操作就是正式的开辟一个空间 EDIDdestination目的地 1这里存储目标数据的指针和索引通常指向目标字符串的起始位置以指示存储的位置 我们来看看vs2019变化里面的变量后会怎么样 这个是我们加了变量之后这个变成了ebp-48h了所以可看到不同的编译器所编写的栈帧都是不一样的 第六步 这里就是把9赋值给ecx寄存器0CCCCCCCCh赋值给eax中 第七步  我们把这个代码拆开来理解 1rep这个是一个前缀指令用于重复执行紧跟其后面的指令直到ecx为0 2stos全名store  String存储字符串 把eax的内容赋值到edi所指向的地址中并把edi递增逐步的把这个全部填满这个空间 3dword全名double word指4个字节word是指2个字节 4ptr  这个是操作数的大小提示符号比如这里就是告诉编译器这个是4个字节4个字节输入顺便告诉编译器接下来是按照特定的字符大小进行操作的比如这里的4个字节 5es这个是寄存器的前缀用于指定内存操作 6[edi]  这个是指是edi这个指向的内存 总体来说就是每次想edi指向的地址一4个字节的大小不断地把eax存储的值传入进去 那么这里的ccccccccc是什么呢我们之前不是会遇到烫烫烫这一长串的代码嘛其实就是这个ccccccc弄出来的比如变量为初始化打出的乱码就是烫烫烫这个烫烫烫实质就是cccccc 程序走到了这里main函数的帧栈正式开辟成功这个是有esp和edp形成的区域为一个函数的作用域接下来就是执行main函数内部的东西了 2生成局部量  这个我们以a为例子 0Ah其实就是把十六机制转换成十进制这个就是10的意思然后这个后面就是把0Ah赋给a这个地址其他都是一样的 3main函数的总结 接下来呢我们main函数里面的就基本结束了后面就是add函数的了我们来总结一下这个main函数是怎么操作的 1首先就是把一个ebp压入栈中然后ebp这个是用来代表基地址的或者就是说存放了基地址 2我们利用edp这个指向esp的位置是我们这个ebp进行调位置指向main的基地址 3我们利用esp这个减去一个数值使esp来想上移动然后就是给main函数一个预留一个空间 4我们利用edi的赋值正式把这个地址赋值给edi可以把更好的寻找到这个空间的首地址所以就是相当于正式开辟了一个内存空间这个空间大小就是我们所预留的空间大小 5然后对于这个空间里面进行初始化把这里面填满c这个东西然后给ecx传值 6对于局部变量的生成利用mov这个指令 接下里就是add这个函数的分析了 4调用函数与传参 前面四行代码  前面两行显然是把b的地址的值通过mov的指令”拷贝”到eax里面去这个mov是其实是转移的意思也可以理解为拷贝的意思然后把eax压入到栈中 后面两行显然也是把a的地址的值通过mov的指令“拷贝”到ecx里面去然后就把ecx压入到栈里面去 我们来画一下这个图示 为什么我们要有这四行指令这个其实就是把形参压入栈里面去了这里我们就可以了解到其实形参和实参是处于两个独立的空间的所以我们就可以知道为什么形参的改变不了实参了答案就在这里所以这四行代码就是建立形参用的  一到四行是为形参做准备那这样的压入栈中真的可以把参数传入到函数里面吗调用的函数该怎么使用我们的参数 我们继续往下看 第五行 call指令这里其实就是一个转移指令符转移到另外一个地方去同时也是为了完成转移后完成原区域的下一个指令那他是怎么实现这个功能的呢我们继续详细了解call指令时把我们下一个指令压入栈中然后这样的话就可以实现转移后可以返回到原地 简单来说原地插个眼后传送去支援最后还可以返回到线上做到有来有回 我们来看看真的是这样嘛由于vs2019是不支持看这个的所以你们可以下载vs2013点击F11然后就可以看到类似于这个的声明  这个就是对于add的一个声明然后这里有个jmp的指令这里就是跳入add函数的意思为转换的操作我前面画的那个方框是那个地址应该是call后面的那个地址 应该是相同的这个我是找了别的图所以不同因为vs2019弄不出来我在网上找了一个这个指令就是想告诉读者有这个操作 接下来就是正式跳转到add函数了 5Add函数 add函数的创建 我们先来看这个这个是不是似曾相识没错跟我们创建main函数的方式一模一样读者可以尝试自己去解读一下这样可以让自己的形象更加深刻我把答案写到下面了 我们来看看现在的栈帧的图该怎么画 变量的生成    运算 这个局部变量的形成是跟前面一样的这里就不多讲了我来看看后面的  第一句是把形参x放入到eax中因为eax的用处有可以用与加法然后第二句再把这个y放入到这个eax中然后根据add指令执行相加我们就的道了结果然后再把eax的值拷贝给z这个变量这个z里面去这个就是运算形参的压入顺序是按照从左往右的根据你设置的函数 函数的返回值和函数返回与销毁的实现 我们按照前面所学的xyz都是在函数调用完会被销毁的 问题1我们该怎么获取这个返回值 问题2esp栈顶指针和ebp栈底指针该何去何从 我们先来看这个return这个代码 这里是把z的值存储到eax中因为我们知道eax的一个用处是存储数据和运算结果把他临时放入到eax中就可以把值返回了第一个问题就迎刃而解了 当然值超出了eax的范围就要用到其他寄存器存储了比如esi等其余寄存器存储  我们再来看看后面的销毁与返回怎么实现的呢我们来看这个指令 pop指令指跳出栈将元素弹出栈以此释放掉 这个是把是三个非易使寄存器给弹出去释放掉他们三个注意这个esp栈顶指针的位置是会变化的 这里是弹出三个寄存器 这个的用处栈不是弹出来了那三个寄存器嘛然后就要收缩调整栈你看0CCh不正是我们之前所弄出来的空间大小嘛 这里是栈的收缩调整  这两行指令其实就是检查是否有栈溢出的哪些错误 cmp这个指令是比较两个 比较基指针EBP和栈指针ESP的值。这通常用于检查栈是否正确对齐或者在调试时检查栈是否被破坏。 call这一段  调用运行时检查函数  __RTC_CheckEsp  这个函数可能是用于检查栈溢出或栈保护的。  051244h  是该函数在内存中的地址。这个调用可能是由编译器插入的用于在运行时检查栈指针是否在函数调用后仍然有效以防止栈溢出攻击或检测栈损坏 这两个是检查安全性的 我们来看后面的指令 第一行就是把ebp的值赋给esp然后ebp会读取地址然后转移到之前main函数的基地址之后再让ebp读取之前的那个地址这里的pop是pop另外一个功能是读取数据的功能实现了这个esp和ebp的转移 根据这个转移最后把这个弹出即可然后就可以跟着下一个指令了 这里的ret是把栈顶的字节安远出栈然后交给EIP来处理这样就可以紧接着这个后面程序的执行即可 我来总结一下add函数的过程 1我们先进入函数的调用先把形参压入到栈里面然后利用call进入到那个函数的声明的地址哪里并且把下一个指令压入到栈里面去然后再利用jmp跳入到那个函数里面 2我们在把局部变量弄出来然后利用add和eax这两个弄西进行运算最后赋值给z 3然后把z的值暂存储在eax中 4运行返回时我们就把三个寄存器弹出去然后ebp会赋给espebp会读取之前的ebp地址进行跳转然后就可以实现这个esp和edp返回原位置 5利用ret来实现后面的程序即可 总结 上面的文章里面都有每小段的总结我们可以根据这些可以解决很多问题
http://www.tj-hxxt.cn/news/232171.html

相关文章:

  • 漂亮的手机网站模板下载2019还有人做网站淘宝客吗
  • 网站容易出现的问题app网站开发湖南
  • 顺的网站建设多少钱深圳设计网站建设
  • 宁波趋势信息科技有限公司seo营销优化
  • 大型门户网站多少钱网站集群建设的意义
  • 空包网站建设成立公司合作协议书范本
  • 深圳网站建设公司招聘电话销售甜蜜高端定制网站
  • 竞价网站做seo建筑设计公司名字
  • 撩人的网站怎么做网站建设需要配置环境么
  • 云南省网站备案要求做背景图获取网站
  • 怎么样通过做网站赚钱吗安徽高端网站建设
  • 楚州网站开发微信商城小程序多少钱
  • 南宁建网站龙岗网站建设企业
  • 网站文章推广如何建设小说网站
  • 巨鹿网站建设网络公司中国万网域名注册服务内容
  • 织梦网站被做跳转网站主机ip查询
  • 加人引流加人网站怎么做黄冈网站制作
  • 网站建设自查情况报告莘庄做网站
  • js判断是手机还是电脑访问网站垂直电商平台有哪些?
  • 宣传式网站网页设计培训传智教育
  • 嘉兴城乡建设网站做报纸版式的网站
  • 呼和浩特做网站的朝阳网站建设 慈云寺
  • 湘潭找工作网站个人的网站建设的目的
  • 哪家成都公司做网站网页游戏平台排名前10名
  • 网站建设和网站开发的区别深圳手机网站公司
  • 网站添加属性物流网站的功能与特色
  • 网络营销做得好的产品什么网站做优化最好?
  • 做网站的联系方式免费培训机构
  • 淘宝客网站WordPress最新注册公司流程及费用
  • 网站设计网页首页介绍如何搭建微信公众号平台