汇编call 命令 解析
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了汇编call 命令 解析相关的知识,希望对你有一定的参考价值。
使用汇编语言中的call命令 ,伴随着一些内容的入栈,那么,入栈的都是一些什么内容呢?它们入栈的顺序是什么样的?
不同的CPU可能有不同的规定。下面只说常见的简单CPU的指令。
常见的CPU的CALL指令(“调用”指令)的功能,就是以下两点:
(1)将下一条指令的所在地址(即当时程序计数器PC的内容)入栈,
(2)并将子程序的起始地址送入PC(于是CPU的下一条指令就会转去执行子程序)。
而子程序结尾处通常都要编写一条RET指令(“返回”指令),RET指令的功能就是一条:
从栈中取出一条数据送入PC。
从上面叙述可以看出,正常情况下,RET指令从栈中取出的一条数据,也就是当初被CALL指令所入栈的下一条指令的所在地址。
因此,RET指令后,CPU的下一条指令就回去执行当初的CALL指令的下一条了。
至于其他操作,如sweetsugar123兄所说的“保护寄存器现场”等等,一般并非CALL指令的功能,而是需要程序员自行在子程序内编写程序实现的。这些操作通常也需要用到堆栈。基于堆栈的“后进先出”性质,这些操作可以不干扰CALL和RET指令的“保存返回地址”的功能。
参考技术A 不同的CPU可能有不同的规定。下面只说常见的简单CPU的指令。常见的CPU的CALL指令(“调用”指令)的功能,就是以下两点:
(1)将下一条指令的所在地址(即当时程序计数器PC的内容)入栈,
(2)并将子程序的起始地址送入PC(于是CPU的下一条指令就会转去执行子程序)。
而子程序结尾处通常都要编写一条RET指令(“返回”指令),RET指令的功能就是一条:
从栈中取出一条数据送入PC。
从上面叙述可以看出,正常情况下,RET指令从栈中取出的一条数据,也就是当初被CALL指令所入栈的下一条指令的所在地址。
因此,RET指令后,CPU的下一条指令就回去执行当初的CALL指令的下一条了。
至于其他操作,如sweetsugar123兄所说的“保护寄存器现场”等等,一般并非CALL指令的功能,而是需要程序员自行在子程序内编写程序实现的。这些操作通常也需要用到堆栈。基于堆栈的“后进先出”性质,这些操作可以不干扰CALL和RET指令的“保存返回地址”的功能。本回答被提问者采纳 参考技术B 不同的CPU可能有不同的规定。下面只说常见的简单CPU的指令。
常见的CPU的CALL指令(“调用”指令)的功能,就是以下两点:
(1)将下一条指令的所在地址(即当时程序计数器PC的内容)入栈,
(2)并将子程序的起始地址送入PC(于是CPU的下一条指令就会转去执行子程序)。
而子程序结尾处通常都要编写一条RET指令(“返回”指令),RET指令的功能就是一条:
从栈中取出一条数据送入PC。
从上面叙述可以看出,正常情况下,RET指令从栈中取出的一条数据,也就是当初被CALL指令所入栈的下一条指令的所在地址。
因此,RET指令后,CPU的下一条指令就回去执行当初的CALL指令的下一条了。
至于其他操作,如sweetsugar123兄所说的“保护寄存器现场”等等,一般并非CALL指令的功能,而是需要程序员自行在子程序内编写程序实现的。这些操作通常也需要用到堆栈。基于堆栈的“后进先出”性质,这些操作可以不干扰CALL和RET指令的“保存返回地址”的功能。 参考技术C 貌似call只有原地址入栈,就是call指令占的地址,因为如果这个地址不入栈的话call调用的子程序返回时会找不到返回的地址, 你随便反汇编一个程序,单步步入CALL,会发现堆栈寄存器只减了4,就是一个DWORD类型的32位的地址啦~~~ 我跟过很多次了= = 参考技术D call word ptr ?[?]是段内调用,只是先把当前指令的下一条指令的ip压栈,然后将?[?]下的内容给ip,然后继续执行. 在压栈时是sp=sp-2,ss:[sp]=压栈的ip值.call dword ptr ?[?]是段间调用,只是先把当前的cs压栈,然后将指令的下一条指令的ip压栈,然后将?[?]下的内容给ip, ?[?+2]的内容给cs,然后继续执行. 这里是sp=sp-2;ss:[sp]=压栈的cs,然后sp=sp-2;ss:[sp]=压栈的ip. 希望对你有用.
批处理命令——call 和 start
一、call命令总结
【1】call命令简介
学过汇编或C的朋友,肯定都知道call指令表示什么意思。其实,在这里它的意思也是一样的。在批处理脚本中,call命令用来从一个批处理脚本中调用另一个批处理脚本。
语法: call [ [Drive:] [Path] FileName [BatchParameters]] [:label [arguments]]
参数: [Drive:][Path] FileName 指定要调用的批处理程序的位置和名称。Filename 参数必须是.bat 或 .cmd 扩展名的类型文件。
BatchParameters 指定批处理程序所需的命令行信息(即参数项)。
调用另一个批处理程序,并且不终止父批处理程序(如果不用call而直接调用别的批处理文件,那么执行完那个批处理文件后将无法返回当前文件并执行当前文件的后续命令)。
call 命令接受用作跳转目标的标签。如果在脚本或批处理文件外使用call,它将不会在命令行起作用。
【2】call命令应用
1. 基本应用。应用示例:新建两个文本文件,一个命名为call1,修改文件的类型为bat,用Notepad++打开编辑内容为:
1 echo running call1
另一个命名为call2,修改文件类型为bat,用Notepad++打开编辑内容为:
1 @echo off 2 echo start 3 call call1.bat 4 echo running call2 5 echo end 6 pause
双击执行call2文件,执行结果如下所示:
过程解析:
可以很清晰的看到,call调用类似于函数调用的执行逻辑:call2相当于执行主函数,在其执行过程中,需要调用到call1函数,当call1执行结束后,call2主函数再继续执行本身的命令,直至整个过程结束。
注意:call1脚本第一行没有再写@echo off语句。因为call2第一行已经关闭了命令回显状态,当call2调用call1时,此设置同样有效,由此可更深入理解调用。
2. 调用标签。应用示例:新建两个文本文件,一个命名为call3,修改文件的类型为bat,用Notepad++打开编辑内容为:
1 @echo off 2 call :label 3 echo 1 4 echo 2 5 6 :label 7 echo 3 8 echo 4
另一个命名为call4,修改文件类型为bat,用Notepad++打开编辑内容为:
1 @echo off 2 call call3.bat 3 pause
双击执行call4文件,执行结果如下所示:
过程解析:
看到这个结果什么感觉?让你想起了什么呢?想不起来啥?一看你若有所茫的样子,就知道你把goto与这个搞混了!请看下文call命令与goto命令的区别。
3. 调用带参数的批处理。应用示例:新建两个文本文件,一个命名为call7,修改文件的类型为bat,用Notepad++打开编辑内容为:
1 echo %1 %2 2 echo %3
另一个命名为call8,修改文件类型为bat,用Notepad++打开编辑内容为:
1 @echo off 2 call call7.bat hello world 123 3 dir c:\\ 4 pause
双击执行call8文件,执行结果如下所示:
【3】call命令与goto命令的区别
call命令的应用示例2中,我们看到了call命令对跳转标签的调用,注意调用时必须在标签名前加冒号,而goto是直接跟标签名。
关于goto命令不懂的可以参见同系列随笔《批处理命令——goto 和 :》
同上例,我们再看看goto的执行效果:新建两个文本文件,一个命名为call5,修改文件的类型为bat,用Notepad++打开编辑内容为:
1 @echo off 2 goto label 3 echo 1 4 echo 2 5 6 :label 7 echo 3 8 echo 4
另一个命名为call6,修改文件类型为bat,用Notepad++打开编辑内容为:
1 @echo off 2 call call5.bat 3 pause
双击执行call6文件,执行结果如下所示:
二、start命令总结
【1】start命令简介
start命令比较复杂。查看其帮助文档的步骤如下:
1. 同时按下“Win + R”键(或者桌面开始-->开始-->运行),打开“运行”窗口,输入“cmd”-->确定。
2. 在打开的命令提示符窗口里,输入start/?-->回车,查看“start”命令的参数和用法说明(注:按任意键可以查看更多后面的内容)示例截图如下:
3. 命令提示符窗口里,按自己的使用需要,输入-->start /具体参数-->回车,即可按自己的需要、在Windows系统里使用“start”命令
【2】start命令应用
1.基本应用。打开系统计算器以及记事本。
新建一个文本文件,命名为start1,修改文件类型为bat,用Notepad++打开编辑内容为:
1 start calc 2 start notepad 3 exit
执行结果:分别打开计算器和记事本,同时终端一闪而过(因为最后exit)。
【3】start命令与call命令的区别
start命令应用示例:新建两个文本文件,一个命名为startmain,修改文件类型为bat,用Notepad++打开编辑内容为:
1 @echo off 2 set a=1 3 pause>nul 4 echo start startchild.bat 5 start startchild.bat 6 echo end start 7 pause>nul 8 echo %b% 9 pause>nul
一个命名为startchild,修改文件类型为bat,用Notepad++打开编辑内容为:
1 @echo off 2 echo %a% 3 set b=20 4 pause>nul
双击执行startmain.bat,观察其运行结果如下图所示:
相同的应用,如果改为call命令:新建两个文本文件,一个命名为callmain,修改文件类型为bat,用Notepad++打开编辑内容为:
1 @echo off 2 set a=1 3 pause>nul 4 echo call callchild.bat 5 call callchild.bat 6 echo end call 7 pause>nul 8 echo %b% 9 pause>nul
一个命名为callchild,修改文件类型为bat,用Notepad++打开编辑内容为:
1 @echo off 2 echo %a% 3 set b=20 4 pause>nul
双击执行callmain.bat,观察其运行结果如下图所示:
分析结果:
应用示例中,在main.bat中定义了变量a,值为1;在child.bat中定义了变量b,值为20。
main.bat首先执行call child.bat,然后child.bat将执行echo %a%,现在能正常显示1。
call完之后,main.bat将执行echo %b%,也能正常显示20。
那么,如果将call改为start,待child.bat执行完再关闭之后,main.bat继续echo %b%,将无法显示变量b的值,而仅相当于执行echo命令,执行结果为:ECHO处于关闭状态。
call的时候,他们拥有同一个壳cmd.exe,在同一个进程当中,所以他们的变量是互通的。
start的时候,他们拥有两个壳cmd.exe,但child.bat可以看成是main.bat的子进程,子进程可以读取父进程中的变量(即a的值)。
总结结论:
对于start,概况二句话:“不同进程不能传值”,“相同进程单向传值,老子传儿子,非儿子传老子”。
对于call,“同一进程,变量互通”。
另外,可以从以下几方面理解start与call命令的区别:
一是调用范围不同:call主要用来进行批处理的内部调用,如call :pend 和一些dos命令的调用如call set test=2,但也可以调用其他可执行文件,而start则不能进行内部调用,但其可以执行基本上所有的外部程序,还可以执行shell,如打开文件夹start "" "%WINDIR%",安装网络打印机start "" "\\\\IP\\Printer"等等。
二是调用方式不同:call是严格意义上而言的调用,在call另一个批处理时是在同一窗体进程里执行,而start则是执行,所以在执行另外一个批处理时是在不同的窗体进程里进行,也就是说在新开启的进程里执行,虽然start可以加入b参数,但其结果却完全不同。如我们使用call set test=2 和 start /b set test=2 看似执行的结果相同,但是我们发现后者有两个进程,而且在窗体里要执行两次exit才能退出,所以当我们使用start来执行一个批处理后最好在被调用的批处理中也加一个exit,否则无法退出被调用的批处理的dos窗体,但是使用call调用时如果在被调用的批处理中存在exit则会直接结束原始和被调用的批处理程序,这是一个非常严重的问题。建议在被调用的批处理中使用goto :eof来取代exit。
三是调用结果不同:call调用不仅可以把参数或变量传给被调用的批处理,而且被调用的批处理也可以设置参数或变量以便回传,而start只能把参数或变量传给被调用的批处理,却不能回传参数或变量,这一点实际上是第二点的延伸。另外,我们还必须注意一点:使用call调用其他批处理时,在被调用的批处理中若我们使用goto命令的时候,建议要使用与原批处理中不同的标签名来跳转,否则可能会跳转到原批处理中而不能保证完整的执行被调用批处理中的所有语句。
http://www.cnblogs.com/Braveliu/p/5078283.html
以上是关于汇编call 命令 解析的主要内容,如果未能解决你的问题,请参考以下文章
Android 逆向使用 Python 解析 ELF 文件 ( Capstone 反汇编 ELF 文件中的机器码数据 | 创建反汇编解析器实例对象 | 设置汇编解析器显示细节 )(代码片段