汇编语句中的 jmp 与 call 指令

2024-08-25 22:52
文章标签 指令 call 语句 汇编 jmp

本文主要是介绍汇编语句中的 jmp 与 call 指令,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

jmpcall 是两条在汇编语言中非常常用的跳转指令,它们虽然都涉及程序控制流的跳转,但在功能和应用场景上有显著的区别。

1. 基本功能和行为

  • jmp 指令:

    • 功能: jmp 用于无条件跳转,直接将程序的执行流跳转到指定的地址。
    • 行为: 执行 jmp 后,程序不会记录跳转前的位置,也不会在执行完目标代码后返回。它只是简单地更改了指令指针(IP/EIP/RIP),程序从新的地址继续执行。
    • 应用场景: jmp 常用于跳转到函数的某个位置、循环控制、跳过某些代码段等。
  • call 指令:

    • 功能: call 用于调用子程序。它不仅跳转到目标地址,还保存了返回地址,以便在子程序执行完毕后能够返回调用点继续执行。
    • 行为: 执行 call 时,当前指令的下一条指令的地址会被压入堆栈(作为返回地址),然后程序跳转到目标地址。子程序执行完后,通过 ret 指令可以从堆栈中弹出返回地址并跳回原来的调用点。
    • 应用场景: call 主要用于函数调用,确保在执行完子程序后程序能够继续从调用点之后的指令执行。

2. 栈操作

  • jmp:

    • jmp 指令不会涉及栈的操作。它只是简单地修改指令指针(IP/EIP/RIP),所以不会保存任何返回地址。
    • 因此,jmp 后执行的代码通常不会返回原位置,除非代码显式使用 jmpcall 来跳回。
  • call:

    • call 指令在跳转前会自动将当前指令的下一条指令的地址压入栈中。这一操作使得在子程序执行完后,程序可以通过 ret 指令从栈中弹出该地址,并跳回到调用点继续执行。
    • 这使得 call 非常适合用于函数调用,因为它支持在执行完子程序后返回原来的调用位置。

3. 结合内核中的 switch_to 例子

  • 在内核的上下文切换中,jmpcall 有不同的应用场景。

    • jmp 的应用: 在 switch_to 宏中,jmp __switch_to 用于直接跳转到上下文切换函数 __switch_tojmp 的作用是切换到另一个任务,并立即开始执行该任务的代码,而不需要保存当前代码的位置,因为上下文切换不需要返回到原来的位置。

    • call 的应用: 如果内核希望在执行完一个子任务后继续执行当前的任务,比如在系统调用或者中断处理程序中,通常会使用 call。它确保任务执行完后能够通过 ret 返回调用点,从而继续执行原来的代码。

  • 内核上下文切换的行为:

    • jmp __switch_to 会导致跳转到 __switch_to 函数,而不需要返回。而 call 会将返回地址(即 1: 标签的地址)保存到栈中,确保在 __switch_to 执行完后能够通过 ret 返回到 1: 处继续执行。
  • #define switch_to(prev,next,last) do {					\unsigned long esi,edi;						\asm volatile("pushfl\n\t"					\"pushl %%ebp\n\t"					\/*** 把esp的内容保存到prev->thread.esp中* 这样该字段指向prev内核栈的栈顶。*/"movl %%esp,%0\n\t"	/* save ESP */		\/*** 将next->thread.esp装入到esp.* 此时,内核开始在next的栈上进行操作。这条指令实际上完成了从prev到next的切换。* 由于进程描述符的地址和内核栈的地址紧挨着,所以改变内核栈意味着改变当前进程。*/"movl %5,%%esp\n\t"	/* restore ESP */	\/*** 将标记为1f的地址存入prev->thread.eip.* 当被替换的进程重新恢复执行时,进程执行被标记为1f的那条指令。*/"movl $1f,%1\n\t"		/* save EIP */		\/*** 将next->thread.eip的值保存到next的内核栈中。* 这样,_switch_to调用ret返回时,就会跳转到next->thread.eip执行。* 这个地址一般情况下就会是1f.*/"pushl %6\n\t"		/* restore EIP */	\/*** 注意,这里不是用call,是jmp,这样,上一条语句中压入的eip地址就可以执行了。*/"jmp __switch_to\n"				\/*** 到这里,进程A再次获得CPU。它从栈中弹出ebp和eflags。*/"1:\t"						\"popl %%ebp\n\t"					\"popfl"						\:"=m" (prev->thread.esp),"=m" (prev->thread.eip),	\/* last被作为输出参数,它的值会由eax赋给它。 */"=a" (last),"=S" (esi),"=D" (edi)			\:"m" (next->thread.esp),"m" (next->thread.eip),	\"2" (prev), "d" (next));				\
    } while (0)

4. 总结

  • jmp:

    • 用于无条件跳转,不保存返回地址。
    • 改变程序执行流,但不会返回到原跳转点。
  • call:

    • 用于调用子程序,保存返回地址。
    • 在子程序执行完毕后,可以通过 ret 返回调用点继续执行。
  • 在操作系统内核中,jmp 常用于上下文切换等不需要返回的场景,而 call 则用于函数调用,确保在执行完毕后返回继续执行。

这篇关于汇编语句中的 jmp 与 call 指令的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1106882

相关文章

Python包管理工具核心指令uvx举例详细解析

《Python包管理工具核心指令uvx举例详细解析》:本文主要介绍Python包管理工具核心指令uvx的相关资料,uvx是uv工具链中用于临时运行Python命令行工具的高效执行器,依托Rust实... 目录一、uvx 的定位与核心功能二、uvx 的典型应用场景三、uvx 与传统工具对比四、uvx 的技术实

Mybatis Plus JSqlParser解析sql语句及JSqlParser安装步骤

《MybatisPlusJSqlParser解析sql语句及JSqlParser安装步骤》JSqlParser是一个用于解析SQL语句的Java库,它可以将SQL语句解析为一个Java对象树,允许... 目录【一】jsqlParser 是什么【二】JSqlParser 的安装步骤【三】使用场景【1】sql语

sql语句字段截取方法

《sql语句字段截取方法》在MySQL中,使用SUBSTRING函数可以实现字段截取,下面给大家分享sql语句字段截取方法,感兴趣的朋友一起看看吧... 目录sql语句字段截取sql 截取表中指定字段sql语句字段截取1、在mysql中,使用SUBSTRING函数可以实现字段截取。例如,要截取一个字符串字

C++使用printf语句实现进制转换的示例代码

《C++使用printf语句实现进制转换的示例代码》在C语言中,printf函数可以直接实现部分进制转换功能,通过格式说明符(formatspecifier)快速输出不同进制的数值,下面给大家分享C+... 目录一、printf 原生支持的进制转换1. 十进制、八进制、十六进制转换2. 显示进制前缀3. 指

MySQL 中的 LIMIT 语句及基本用法

《MySQL中的LIMIT语句及基本用法》LIMIT语句用于限制查询返回的行数,常用于分页查询或取部分数据,提高查询效率,:本文主要介绍MySQL中的LIMIT语句,需要的朋友可以参考下... 目录mysql 中的 LIMIT 语句1. LIMIT 语法2. LIMIT 基本用法(1) 获取前 N 行数据(

MySQL中动态生成SQL语句去掉所有字段的空格的操作方法

《MySQL中动态生成SQL语句去掉所有字段的空格的操作方法》在数据库管理过程中,我们常常会遇到需要对表中字段进行清洗和整理的情况,本文将详细介绍如何在MySQL中动态生成SQL语句来去掉所有字段的空... 目录在mysql中动态生成SQL语句去掉所有字段的空格准备工作原理分析动态生成SQL语句在MySQL

Go 语言中的select语句详解及工作原理

《Go语言中的select语句详解及工作原理》在Go语言中,select语句是用于处理多个通道(channel)操作的一种控制结构,它类似于switch语句,本文给大家介绍Go语言中的select语... 目录Go 语言中的 select 是做什么的基本功能语法工作原理示例示例 1:监听多个通道示例 2:带

mysql的基础语句和外键查询及其语句详解(推荐)

《mysql的基础语句和外键查询及其语句详解(推荐)》:本文主要介绍mysql的基础语句和外键查询及其语句详解(推荐),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋... 目录一、mysql 基础语句1. 数据库操作 创建数据库2. 表操作 创建表3. CRUD 操作二、外键

MySQL INSERT语句实现当记录不存在时插入的几种方法

《MySQLINSERT语句实现当记录不存在时插入的几种方法》MySQL的INSERT语句是用于向数据库表中插入新记录的关键命令,下面:本文主要介绍MySQLINSERT语句实现当记录不存在时... 目录使用 INSERT IGNORE使用 ON DUPLICATE KEY UPDATE使用 REPLACE

Nginx指令add_header和proxy_set_header的区别及说明

《Nginx指令add_header和proxy_set_header的区别及说明》:本文主要介绍Nginx指令add_header和proxy_set_header的区别及说明,具有很好的参考价... 目录Nginx指令add_header和proxy_set_header区别如何理解反向代理?proxy