您现在的位置:首页 >> 基础算法 >> window基础 >> 内容

Delphi中栈内存的分配ASM代码解析

时间:2011/9/3 15:32:13 点击:

  核心提示:栈内存分配函数,注意这里采用的是register参数传递方式,所以这里size参数将放在eax中!functionStackAlloc(Size:integer):Pointer;register;a...
栈内存分配函数,注意这里采用的是register参数传递方式,所以这里size参数将放在eax中!
function StackAlloc(Size:integer):Pointer;register;
asm
  pop ecx;//将返回地址弹出到ecx
  mov edx,esp;//将弹出后esp指针存放在edx中
  add eax,3
  and eax,not 3;//这里主要是将eax(即size)取4的整数,因为栈的操作都是4字节的
  cmp eax,4092;//比较取值后size与一个页的大小(4092是为后面留下的,因为压栈本身还有4字节)
 @@1:
  sub esp,4092;//如果size大于一页的话,先将esp减4092(即增加栈空间)
  push eax//压入eax,这里将补上4字节空间,这样就是4096了,为什么要这一步呢?因为如果我们
          //不是一步一步按页分配,那么我们可能会超出栈范围,如果一步一页,那么如果超出范围
          //那么这个时候push操作就会发生异常。
  sub eax,4096  //eax减去4096,剩下的再分析
  jns @@1  //如果剩下的为正数,说明还要按整页来分配
  add eax,4096 //如果为负数,就加上4096,这个时候eax的值就是零头的值了
 @@2:
  sub esp,eax //再按具体的零头分配栈空间
  mov eax,esp //将这个时候的esp值返回到eax,就是返回值了
  push edx //将原始的esp压入栈中
  mov edx,esp
  sub edx,4 //使edx的值存放它自己将压入到的栈地址
  push edx //压入,便于释放时候来测试是否是此快内存
  push ecx //压入此函数的返回地址,便于函数退出时候返回到断点或者呼叫函数中
end;

而栈内存的清除到是很简单了,因为栈内存中存放了最初的esp地址,所以很容易就可以恢复到初始状态:

procedure StackFree(P:Pointer);register;
asm
 pop ecx  //保存返回地址到ecx寄存器中
 mov edx,dword ptr [esp] //将当前的esp内容放在edx中
 sub eax,8 //将P的地址减8字节,其实这个时候应该指向测试的内存块
 cmp edx,esp //比较,如果相等的话,表示此内存的确是栈分配函数分配的
 jne @@1 //不是的话直接退出,不能强行释放,否则的话,呵呵!
 cmp edx,eax //再次确认,如果通过的话就可以大胆释放了
 jne @@1
 mov esp,dword ptr [esp+4] //直接将原始的栈指针恢复就可以了达到释放栈空间的目的了
@@1:
 push ecx //压入返回地址,便于退出到呼叫函数中!
end;

这段代码虽然简单,但技术含量极高,特别是多次分配,每次都有push操作,看似多此一举,其实是步步探测,主要栈空间一越界就会异常,防止此后的其他操作发生!

作者:网络 来源:转载
共有评论 0相关评论
发表我的评论
  • 大名:
  • 内容:
  • 盒子文章(www.2ccc.com) © 2022 版权所有 All Rights Reserved.
  • 沪ICP备05001939号