记得刚学多线程的时候, 碰到一个结构:


//Delphi 的语法描述
PContext = ^TContext;
_CONTEXT = recordContextFlags: DWORD;Dr0: DWORD;Dr1: DWORD;Dr2: DWORD;Dr3: DWORD;Dr6: DWORD;Dr7: DWORD;FloatSave: TFloatingSaveArea;SegGs: DWORD;SegFs: DWORD;SegEs: DWORD;SegDs: DWORD;Edi: DWORD;Esi: DWORD;Ebx: DWORD;Edx: DWORD;Ecx: DWORD;Eax: DWORD;Ebp: DWORD;Eip: DWORD;SegCs: DWORD;EFlags: DWORD;Esp: DWORD;SegSs: DWORD;
end;

从这个结构中可以基本洞察多线程的基本原理:
1、在切换到另一个线程之前, 先把当前线程在寄存器中的数据保存在这个结构;
2、重新切回线程时, 再才这个结构中读出相关数据到寄存器, 从而继续运行...



压栈、出栈也是类似的道理.

一个程序包含若干子程序, 子程序中一般会有自己的参数或局部变量.
在执行这个子程序前, 应该先把寄存器中的相关数据暂存一下(子程序也要使用寄存器), 这就是所谓的压栈(PUSH);
等子程序执行完毕, 再把之前压到栈中的数据取回(而让程序继续执行), 这就是所谓的出栈(POP).



什么是 "栈"?

程序把内存划分了若干区域, 其中有 "全局数据区" 和 "局部数据区".

全局数据所在的位置叫 "堆";
局部数据(局部变量、局部常量、子程序参数)所在的位置叫 "栈", 也叫 "堆栈".

对 "堆" 和 "栈", 前人给出了不同的使用规则:
"堆" 中的数据一般是由下到上排列;
"栈" 的数据则完全相反, 是由下到上排列.

验证 "堆" 与 "栈" 不同的数据排列方式:


; Test17_1.asm
.386
.model flat, stdcallinclude    windows.inc
include    kernel32.inc
include    masm32.inc
include    debug.inc
includelib kernel32.lib
includelib masm32.lib
includelib debug.lib.data?GlobalVal1 dd ?GlobalVal2 dd ?GlobalVal3 dd ?
.codemain procLOCAL LocalVal1:dword, LocalVal2:dword, LocalVal3:dword;获取全局变量地址(地址是顺序递增的):PrintHex offset GlobalVal1  ;00403054PrintHex offset GlobalVal2  ;00403058PrintHex offset GlobalVal3  ;0040305C;获取局部变量地址(地址是顺序递减的):lea eax, LocalVal1PrintHex eax                ;0012FFBClea eax, LocalVal2PrintHex eax                ;0012FFB8lea eax, LocalVal3PrintHex eax                ;0012FFB4ret
main endp
end main

压栈与出栈的顺序:


.386
.model flat, stdcallinclude    windows.inc
include    kernel32.inc
include    masm32.inc
include    debug.inc
includelib kernel32.lib
includelib masm32.lib
includelib debug.lib.dataval1 dd 111val2 dd 222val3 dd 333
.code
main procpush val1push val2push val3;压栈完毕, 接着出栈pop val1pop val2pop val3;查看取回的数据:PrintDec val1  ;333PrintDec val2  ;222PrintDec val3  ;111;怎么反了? 这就是常说的 "栈中的数据是先进后出"! 让后进的先出就好了.ret
main endp
end main

根据 "栈" 先进后出的特点, 写一个变量换值的程序:


; Test17_3.asm
.386
.model flat, stdcallinclude    windows.inc
include    kernel32.inc
include    masm32.inc
include    debug.inc
includelib kernel32.lib
includelib masm32.lib
includelib debug.lib.dataval1 dd 111val2 dd 999
.codemain procpush val1push val2pop val1pop val2;现在 val1 和 val2 的值已经交换PrintDec val1  ;999PrintDec val2  ;111ret
main endp
end main

如果仅是交换变量的值, 可以使用 XCHG 指令:


; Test17_4.asm
.386
.model flat, stdcallinclude    windows.inc
include    kernel32.inc
include    masm32.inc
include    debug.inc
includelib kernel32.lib
includelib masm32.lib
includelib debug.lib.dataval1 dd 111val2 dd 999
.codemain proc;xchg va1, val2 ;指令都不支持对两个变量直接操作, 需要用个寄存器中转下mov  eax, val1xchg eax, val2mov  val1, eaxPrintDec val1   ;999PrintDec val2   ;111ret
main endp
end main

根据上面的原理, 也可以方便写出一个翻转字符串的函数:


; Test17_5.asm
.386
.model flat, stdcallinclude    windows.inc
include    kernel32.inc
include    masm32.inc
include    debug.inc
includelib kernel32.lib
includelib masm32.lib
includelib debug.lib.dataszText db 'Hello World!', 0
.codemain proc;把字符串中的字符逐个压入栈中mov ecx, sizeof szText - 1  ;把字符串长度(将要反复的次数)给 ecx, 没包括结束记号xor esi, esi                ;清空 esi, 准备用作数组索引
@@: movzx eax, szText[esi]      ;循环读出并压栈push eaxinc esiloop @B;从栈中逐个取出并写入字符串mov ecx, sizeof szText - 1xor esi, esi
@@: pop eaxmov szText[esi], alinc esiloop @BPrintString szText  ;!dlroW olleHret
main endp
end main
;做这个程序也有更好的方案, 譬如用 movs

学 Win32 汇编[17]: 关于压栈(PUSH)与出栈(POP) 之一相关推荐

  1. 根据入栈顺序判断出栈顺序的合法性

    这道题不管是面试还是笔试的选择题都非常爱出的一道题 题目描述: 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序.假设压入栈的所有数字均不相等.例如序列1,2,3,4 ...

  2. 数据结构实验之栈七:出栈序列判定

    题目描述 给一个初始的入栈序列,其次序即为元素的入栈次序,栈顶元素可以随时出栈,每个元素只能入栈依次.输入一个入栈序列,后面依次输入多个序列,请判断这些序列是否为所给入栈序列合法的出栈序列. 例如序列 ...

  3. 栈的弹出函数pop()实现方案探讨

    多日前,我在blog发表了对<多任务下的数据结构与算法>一书的评论,在与作者的探讨中,我们就栈的弹出函数设计有比较大的分歧,详见http://blog.csdn.net/lanphaday ...

  4. 根据入栈顺序判断出栈顺序是否合理

    def is_pop_order(push, pop):"""根据入栈顺序判断出栈顺序是否合理:param push: 入栈顺序:param pop: 出栈顺序:retu ...

  5. 有苦有乐的算法 --- 自定义一个栈,实现压栈(push)、弹栈(pop)、获取站内最小值(getmin)

    题目 自己定义一个栈的class,要求此栈有三个方法push.pop.getmin push:往栈中压入一个数据 pop:从栈中弹出一个数据 gitmin:过去这个栈中最小的数据单不弹出 解析 准备两 ...

  6. 数据结构栈(顺序栈、链栈、插入push、删除pop)、队(循环队,链队、入队push,出队pop)知识点梳理

    数据结构栈知识点梳理 一 栈的定义 栈(stack)是限定仅在表尾进行插入和删除操作的线性表 不含任何元素的栈称为空栈 允许插入和删除的一端成为栈顶(top),另一端称为栈底(bottom) 具有LI ...

  7. 【数据结构与算法】栈的基本运算(出栈、入栈、销毁栈等)及源码(顺序栈和链式栈)

    一.顺序栈 .h文件 #include <iostream> using namespace std;#define STACKSIZE 100 typedef int DataType; ...

  8. (学习日记)关于a1,a2,a3,...,an共n个元素依次入栈其可能出栈的排列数的计算(catalan数)...

    常规分析(如果对下面的分析感觉比较迷惑的,可以看看下面这个分析http://blog.csdn.net/wind__fantasy/article/details/5398358) 首先,我们设f(n ...

  9. 学 Win32 汇编[27] - 乘除指令: MUL、IMUL、DIV、IDIV

    MUL: 无符号乘 ;影响 OF.CF 标志位 ;指令格式: ;MUL r/m ;参数是乘数;如果参数是 r8/m8, 将把 AL 做乘数, 结果放在 AX ;如果参数是 r16/m16, 将把 AX ...

最新文章

  1. vs2010设置boost开发环境
  2. 架构师实践日 · 6.30 杭州站 | 视觉 AI 技术如何助力行业提升?来西子湖畔与业内大咖面对面交流!
  3. iphone XCode调试技巧之EXC_BAD_ACCESS中BUG解决
  4. 检索出现次数的SQL语句
  5. JAVA中的Font
  6. CVPR 2017论文集锦
  7. boost::python::detail::is_string_literal相关的测试程序
  8. android 格式化代码
  9. 中科院计算机学院研究生招生名额,中科院研究生招生
  10. 10 行代码判定色*情*图片
  11. 堪称神级的Spring Boot手册,从基础入门到实战进阶
  12. 【ubuntu】出现device not managed连接不上网络
  13. 小米note2鸿蒙ROM,小米Note2官方原版系统rom线刷刷机包_小米Note2线刷官方包
  14. 大学生职业生涯规划计划与路径_大学生职业生涯的规划路径
  15. 透镜成像、眼球成像、小孔成像原理
  16. ubuntu gnome桌面农历日历显示
  17. 计算机考研360能去哪里,计算机专业考研,有什么好的211院校推荐?
  18. 贝塞尔曲线想到的--真的很美,但是有时很丑
  19. 服务器温度显示过高,服务器机房温度过高
  20. 硬件知识:电源开关上的“1“和“0“分别是什么意思

热门文章

  1. Permission denied 故障
  2. cnpm搭建私有仓库
  3. 在linux下安装配置svn独立服务器
  4. 【推导】【线段树】hdu5929 Basic Data Structure
  5. 2015 年最受 Linux 爱好者欢迎的软硬件大盘点
  6. 如何使用Junit进行单元测试
  7. JS break语句和continue语句
  8. python压缩与解压缩
  9. 手撕一个spirng IoC的过程
  10. 九爷带你了解 nginx 日志配置指令详解