堆栈

Windbg实用手册

本秂侑毒 提交于 2020-02-24 08:58:01
Windbg工作中用的不多,所以命令老是记不住,每次使用都要重新查命令,挺烦。 趁这次培训的机会好好测试和总结了一下,下次再用就方便多了。 在这里一起共享一下,如果有错误,请指正。 基本知识和常用命令 (1) Windbg下载地址 http://msdn.microsoft.com/en-us/windows/hardware/gg463009.aspx 安装完后执行windbg –I将Windbg设置成默认调试器 (2) Windbg的命令分为标准命令,原命令和扩展命令,输入问号(?)可以显示所有的标准命令的帮助信息; 元命令以一个点(.)开始,输入.help可以显示所有的原命令的帮助信息;扩展命令以叹号(!)开始。 所有命令的具体用法可以通过F1查看Windbg的帮助文件。 (3) 通过设置符号文件路径,让Windbg自动从微软网站更新系统Dll的符号文件 SRV*d:\symbols* http://msdl.microsoft.com/download/symbols (4) 用分号(;)作为分隔符,可以在一行输入多条命令 (5) 按上下箭头可以浏览和选择以前输入过的命令 (6) Ctrl+Break终止一个很长时间没有完成的命令, Ctrl+Break也可以让正在运行的程序暂停 (7) Windbg默认的数值进制一般是16, 可以通过n命令查看和设置当前进制

C#基础:简述.NET中堆栈和堆的特点和差异

孤人 提交于 2020-02-19 10:56:15
一、前言 .NET提供了垃圾回收机制,使程序员从内存管理中被解放出来。但这并不代表程序员就无须了解分配的对象是如何被回收的。更重要的是,一些非托管的资源仍然需要程序员小心地分配与回收。 理解堆和堆栈是理解内存管理的基础。每一个.NET程序都最终会运行在一个操作系统进程中,假设这个操作系统是传统的32位的,那每个.NET程序都可以拥有一个4GB的虚拟内存。.NET会在这个4GB的内存块中开辟出三块内存分别作为堆栈、受托管的堆和非托管的堆。 二、.NET中的堆栈 .NET中的堆栈用来存储值类型的对象和引用类型对象的引用,堆栈的分配是连续的,在.NET程序中,始终存储了一个特殊的指针指向堆栈的尾部,这样一个堆栈内存的分配就直接从这个指针指向的内存位置开始向下分配。下图展示了.NET的堆栈分配方式。 如上图所示,堆栈上的地址从高位开始往低位分配内存,.NET只需要保存一个堆栈指针指向下一个未分配内存的内存地址。对于所有需要分配的对象,依次分配到堆栈中,其释放也严格按照栈的逻辑,依次进行退栈。这里提到的“依次”,是指按照变量的作用域进行的。考虑下面的代码: ClassA a = new ClassA(); a.intA = 1; a.intB = 2; 这里假设ClassA是一个引用类型,则堆栈中依次需要分配的是a的引用、a.intA和a.intB。当a的作用域结束后

节选:论调用约定

时光毁灭记忆、已成空白 提交于 2020-02-18 19:25:07
以下内容节选自: http://blog.vckbase.com/arong/archive/2004/06/09/409.aspx?Pending=true#Post ...... stdcall调用约定 stdcall很多时候被称为pascal调用约定,因为pascal是早期很常见的一种教学用计算机程序设计语言,其语法严谨,使用的函数调用约定就是stdcall。在Microsoft C++系列的C/C++编译器中,常常用PASCAL宏来声明这个调用约定,类似的宏还有WINAPI和CALLBACK。 stdcall调用约定声明的语法为(以前文的那个函数为例): int __stdcall function(int a,int b) stdcall的调用约定意味着:1)参数从右向左压入堆栈,2)函数自身修改堆栈 3)函数名自动加前导的下划线,后面紧跟一个@符号,其后紧跟着参数的尺寸 以上述这个函数为例,参数b首先被压栈,然后是参数a,函数调用function(1,2)调用处翻译成汇编语言将变成: push 2 第二个参数入栈 push 1 第一个参数入栈 call function 调用参数,注意此时自动把cs:eip入栈 而对于函数自身,则可以翻译为: push ebp 保存ebp寄存器,该寄存器将用来保存堆栈的栈顶指针,可以在函数退出时恢复 mov ebp,esp 保存堆栈指针

单片机启动文件

生来就可爱ヽ(ⅴ<●) 提交于 2020-02-17 14:47:58
初始化堆栈指针SP 初始化PC指针 初始化中断向量表 配置系统时钟 调用C库函数_main,最终去到C的世界 启动代码通常都烧写在flash中,它是系统一上电就执行的一段程序,它运行在任何用户c代码之前。上电后,arm处理器处于arm态,运行于管理模式,同时系统所有中断被禁止,pc到地址0处取指令执行。一个可执行映像文件必须有个入口点,而能放在rom起始处的映像文件的入口地址也必须设置为0.在汇编语言中,我们已经说过怎样定义一个程序的入口点,当工程中有多个入口点时,需要在连接器中使用-entry指出程序的入口点。如果用户创建的程序中,包含了main函数,则与c库初始化代码对应的也会有个入口点。 总的来说,启动代码主要完成两方面的工作,一是初始化执行环境,例如中断向量表、堆栈、i/o等;二是初始化c库和用户应用程序。在第一阶段,启动代码的人物可以描述为: (1)建立中断向量表; (2)初始化存储器; (3)初始化堆栈寄存器; (4)初始化i/o以及其他必要的设备; (5)根据需要改变处理器的状态。 -->建立中断向量表 初始化代码必须建立好中断向量表,以备应用程序后续使用。如果系统的地址0处是rom,则中断向量表直接是一些跳转指令就可以了,他们转到相应的中断处理函数执行。如果系统的0地址处不是rom,则中断向量表是通过动态的方式创建的,这主要是通过存储器映射的方式来实现:即上电后

函数调用约定

ε祈祈猫儿з 提交于 2020-02-16 22:17:48
在C语言中,假设我们有这样的一个函数: int function(int a,int b) 调用时只要用result = function(1,2)这样的方式就可以使用这个函数。但是,当高级语言被编译成计算机可以识别的机器码时,有一个问题就凸现出来:在CPU中,计算机没有办法知道一个函数调用需要多少个、什么样的参数,也没有硬件可以保存这些参数。也就是说,计算机不知道怎么给这个函数传递参数,传递参数的工作必须由函数调用者和函数本身来协调。为此,计算机提供了一种被称为栈的数据结构来支持参数传递。 栈是一种先进后出的数据结构,栈有一个存储区、一个栈顶指针。栈顶指针指向堆栈中第一个可用的数据项(被称为栈顶)。用户可以在栈顶上方向栈中加入数据,这个操作被称为压栈(Push),压栈以后,栈顶自动变成新加入数据项的位置,栈顶指针也随之修改。用户也可以从堆栈中取走栈顶,称为弹出栈(pop),弹出栈后,栈顶下的一个元素变成栈顶,栈顶指针随之修改。 函数调用时,调用者依次把参数压栈,然后调用函数,函数被调用以后,在堆栈中取得数据,并进行计算。函数计算结束以后,或者调用者、或者函数本身修改堆栈,使堆栈恢复原装。 在参数传递中,有两个很重要的问题必须得到明确说明: 当参数个数多于一个时,按照什么顺序把参数压入堆栈 函数调用后,由谁来把堆栈恢复原装 在高级语言中,通过函数调用约定来说明这两个问题

Slf4j打印异常的堆栈信息

前提是你 提交于 2020-02-15 07:01:13
一、前言   直接用logger.info("异常信息为:"+e)或者logger.info(e.getMessage())只能记录到异常的描述信息,却没有其异常具体发生在哪一行代码。 这样即使通过日志发现出现了异常,也没法马上定位问题。 因此就催生了一个想法,打印日志是否能像在IDE本地跑程序时出现未捕获的异常时,控制台能打印出完整的错误堆栈信息。 二、问题场景   日常开发中,经常在service实现层使用try-catch-finally保证代码的健壮性, 直接用logger.info("异常信息为:"+e)或者logger.info(e.getMessage())只能记录到异常的描述信息,无法打印完整异常堆栈信息,无法定位其异常具体发生在哪一行代码,当面对比较复杂的代码,那么排查问题将会非常麻烦。 下文将简单重现这类场景,并得到相应的解决方法。 1、不加try-catch 示例: @GetMapping("/hello") public String sayHello(){ logger.info("hello Sfl4j + logback......"); int i = 3/0; return helloService.sayHello(); } 运行结果: 即:当不加try-catch的时候,当出现了意料之外的运行时异常,控制台是能够能打印出完整的错误信息。 2

精读《V8 引擎 Lazy Parsing》

|▌冷眼眸甩不掉的悲伤 提交于 2020-02-15 05:45:55
1. 引言 本周精读的文章是 V8 引擎 Lazy Parsing ,看看 V8 引擎为了优化性能,做了怎样的尝试吧! 这篇文章介绍的优化技术叫 preparser ,是通过跳过不必要函数编译的方式优化性能。 2. 概述 & 精读 解析 Js 发生在网页运行的关键路径上,因此加速对 JS 的解析,就可以加速网页运行效率。 然而并不是所有 Js 都需要在初始化时就被执行,因此也不需要在初始化时就解析所有的 Js!因为编译 Js 会带来三个成本问题: 编译不必要的代码会占用 CPU 资源。 在 GC 前会占用不必要的内存空间。 编译后的代码会缓存在磁盘,占用磁盘空间。 因此所有主流浏览器都实现了 Lazy Parsing(延迟解析),它会将不必要的函数进行预解析,也就是只解析出外部函数需要的内容,而全量解析在调用这个函数时才发生。 预解析的挑战 本来预解析也不难,因为只要判断一个函数是否会立即执行就可以了,只有立即执行的函数才需要被完全解析。 使得预解析变复杂的是变量分配问题。原文通过了堆栈调用的例子说明原因: Js 代码的执行在堆栈上完成,比如下面这个函数: function f(a, b) { const c = a + b; return c; } function g() { return f(1, 2); // The return instruction pointer

EBP寻址

别等时光非礼了梦想. 提交于 2020-02-14 14:42:53
前言:比起ESP寻址的方式,EBP需要去理解下其中的含义,所以记录下! 个人理解: 1、EBP和ESP之间的关系 起初-1 相隔 ----> 在没进CALL之前,会先将调用CALL的参数先压入堆栈,堆栈中EBP寄存器中的地址是在ESP寄存器中的地址之下, 自己理解为相隔 中间-2 相等 ----> 进入CALL之后,EBP寄存器会先把保存的地址先压入堆栈中保存,然后再保存ESP寄存器中的地址,这里就可以理解为ESP不变,将EBP进行提升栈顶的操作 中间-3 相隔 ----> 因为调用了CALL,那么就会进行一系列的运算,那么肯定需要堆栈中的空间,那么ESP地址就会上升 中间-4 相等 ----> 当调用完了之后,当前EBP寄存器保存的就是之前的ESP的地址,现在就会返回给ESP寄存器,堆栈需要保持平衡 末尾-5 相隔 ----> 堆栈到现在还没有完全保持平衡,还需要把EBP的地址返回给EBP寄存器,然后出了CALL之后,还需要指令进行外/内平衡的操作保持真正的堆栈平衡! 汇编体现: 00401000 > 6A 01 push 0x1 ; 压入堆栈0x1 00401002 6A 02 push 0x2 ; 压入堆栈0x2 00401004 E8 3C000000 call CRACKME.00401045 ; 调用call 00401045 00401009 83C4 08 add

堆栈里的秘密行动:劫持执行流

拈花ヽ惹草 提交于 2020-02-11 10:50:07
前情回顾 : 线程老哥执行memcpy越界访问溢出,堆栈里的一众对象难逃噩运。 详情参见: 堆栈里的悄悄话——智能指针 神秘的0xCC “去吧,为了首领的伟大理想出发” 我是一段二进制代码shellcode,0xCC大人精心创造了我,一同诞生的还有一个HTML表单文件小P,我就栖身在小P的身上,随着一个POST请求,我们朝着目标奔去。 很快我们就抵达目的地,这是一个Linux帝国,无数的数据包在这里来来往往。 “这里可真热闹” “嘘,先别说话,马上要经过防火墙,藏好了,可别被发现了”,小P一把捂住了我的嘴。 说完我们就来到了防火墙面前,当差的守卫查看了我们的源IP和端口,又看了目的IP和目的端口,接着瞟了一眼负载数据,当他望向我这边时,我紧张的大气都不敢出一声,把头深深的埋着。 守卫凶神恶煞的问到:“你是去80端口的?这里面装的是什么?” “回大人的话,这里面是个HTML表单,这单业务比较急,还望大爷行个方便”,小P一边说一边悄悄给守卫的衣袖里塞了一些银两。 “走吧,放行!”,总算等来了守卫的这句话。 通过了安检,我俩被安排到了一个队列等待,一会儿,一个自称是Apache公司的线程大哥把我们取走了。 栈溢出 & Stack Cannary 线程大哥把我俩放到了一片陌生的区域。 “你等我一下,我去打听下情况”,小P叮嘱完我后,和隔壁一个对象聊了起来。 “我打听清楚了,这里是进程的堆区

JS数据类型和堆栈+变量比较和值的复制+参数传递和类型检测

…衆ロ難τιáo~ 提交于 2020-02-10 23:26:10
变量命名 变量名:字母 数字 下划线 美元符$ jquery: $ $.each() $ === jQuery underscore( js的一个函数库) : _ _.each() 关键字 : if for 保留字 : class 推荐有意义的命名: buttonCancel button_cancel btnCancel 数据类型和堆栈 基本类型(可以修改) : 4 str true undefined null 引用类型(不能修改) : { } [ ] var score = 40; score = 50; 上面属于覆盖,不属于修改 var str = "hello"; var newStr = str.replace("h", ""); document.write( str + "/" + newStr); 字符串操作返回新的字符串,原字符串没有改变 var obj = {}; console.log(obj); obj.name = "cyy"; obj.age = 25; obj.name = "cyy2"; delete obj.age; console.log(obj); 引用类型的属性可以添加,可以修改,可以删除 var name = "cyy"; name.age = 25; console.log(name.age);//undefined