(学习笔记)3.6 控制(3.6.8 switch语句)

news2026/3/20 22:11:10
文章目录线索栏笔记栏1.跳转表高效多重分支的核心2. 编译实现通用步骤以图3-22/3-23示例 switch_eg为例3. 跳转表数据结构汇编片段4. GCC对C语言的扩展计算goto5. 练习题练习题3.30练习题3.31 图3-24总结栏线索栏核心机制编译器在什么条件下会使用跳转表 (jump table)​ 来实现 switch语句相比一长串if-else跳转表的主要优势是什么实现三步曲实现一个基于跳转表的 switch语句汇编代码通常遵循哪三个关键步骤偏移、检查、跳转索引转换为什么在汇编代码中通常先对 switch的变量做一次减法例如 subq $100,%rdi这步操作在C语言扩展实现中对应什么边界检查技巧汇编代码如何高效地检查转换后的索引是否在跳转表范围内为什么可以使用无符号比较跳转表结构跳转表在汇编代码.rodata段中是如何声明的它如何编码不同 case值包括连续、重复、缺失的情况对应的目标地址逆向工程给定一个 switch语句的汇编代码片段和其跳转表如何系统地逆向推导出原始C代码中所有case的值和对应的代码块练习题3.30 3.31笔记栏1.跳转表高效多重分支的核心1适用条件当 case数量较多如4个且值相对密集时GCC会使用跳转表。2优势执行时间与 case数量无关仅为一次数组索引和一次间接跳转。这是典型的“以空间换时间”。3数据结构一个地址数组表项 i是当开关索引值等于 i时应跳转的代码地址。2. 编译实现通用步骤以图3-22/3-23示例 switch_eg为例C函数long switch_eg(long n, long v) { … switch(n) { … } }1计算索引index n - 100。将原 case值范围 (100-106) 平移至以0为起点 (0-6)。汇编subq $100, %rdi 结果在 %rsi2边界检查比较 index是否 6。利用无符号比较当 index为负数即原 n 100时会因其巨大的无符号表示而判定为 6从而跳转到默认 (default) 块。汇编cmpq $6, %rsi; ja .L83间接跳转通过 index从跳转表 jt中取出目标地址并跳转。汇编jmp *.L4(,%rsi,8)3. 跳转表数据结构汇编片段.section.rodata.align8.L4:# 跳转表基地址.quad.L3 # index0(n100):跳转到.L3(loc_A).quad.L8 # index1(n101):跳转到.L8(default,缺失case).quad.L5 # index2(n102):跳转到.L5(loc_B).quad.L6 # index3(n103):跳转到.L6(loc_C).quad.L7 # index4(n104):跳转到.L7(loc_D).quad.L8 # index5(n105):跳转到.L8(default,缺失case).quad.L7 # index6(n106):跳转到.L7(loc_D 与case104相同)1处理重复casecase 104和 case 106指向同一代码块 (.L7)。2处理缺失casecase 101和 105指向默认块 (.L8)。3处理fall throughcase 102的代码块 (.L5) 末尾没有​ jmp指令执行会“落入” case 103的代码块 (.L6)。4. GCC对C语言的扩展计算goto在教材提供的等价的C扩展代码 switch_eg_impl中使用 运算符获取代码标签的地址从而构造跳转表并使用 goto *jt[index]进行间接跳转。这帮助我们理解汇编指令 jmp *.L4(,%rsi,8)的含义。5. 练习题练习题3.30已知1x在 %rdi。2首条指令addq $1, %rdi。这意味着索引计算为 index x 1。3比较指令cmpq $8, %rdi。检查 index是否 8。4跳转表有9项索引0~8。解答A. case值因为 index x 1 且 ja .L2对应默认所以有效的 index是 0~8对应 x为 -1 ~ 7。但 case值通常是合理的整数所以应为 0~7​ 以及可能的 -1。结合跳转表结构推断case值为0 (index1), 1(index2), 2(index3), 3(index4), 4(index5), 5(index6), 6(index7)。index0和 index8对应默认分支。B. 多标号情况跳转表第6、7行相同 (.L7)第3、10行相同 (.L5)。因此case 2和 case 6共享同一个代码块 (.L7)。case 0和 case 4? 等等需要映射index1对应 x0跳 .L5index5对应 x4跳 .L2(默认)不对。index9对应 x8超范围。仔细看.L40是 .L9(可能对应某个case) .L48 * 8是 .L5。所以 index0(x-1) 和 index8(x7) 都跳 .L5不.L4表第1项是 .L9。所以多标号是case -1和 case 7共享代码块 .L9​ (如果 .L40对应 x-1)但更合理的推断是 case值为 0-6 其中 case 1和 case 5共享代码块 .L5 case 3和 case 4共享代码块 .L7。练习题3.31 图3-24已知汇编代码逻辑和跳转表。逆向推导1计算索引a在 %rdi。指令 subq $50, %rdi index a - 50。2边界检查cmpq $6, %rdi; ja .L2。索引范围 0~6 有效对应原 a为 50~56。3分析跳转表​ (7项).L8:.quad.L3 # index0(a50).quad.L2 # index1(a51)-default.quad.L5 # index2(a52).quad.L6 # index3(a53).quad.L7 # index4(a54).quad.L7 # index5(a55)-与54相同.quad.L5 # index6(a56)-与52相同4映射代码块.L3(a50): movq %rdx, %rdi; jmp .L4 此块修改了参数 c(%rdx)且无 break(jmp)会 fall through。.L5(a52, 56): movq %rdx, %rax; xorq $15, %rax; movq %rax, %rdx; 计算 c ^ 15并赋回 c? 不看后面 movq %rax, (%r9)是赋值给 *dest。所以这是计算 val。.L6(a53): movq %rdx, %rax; movq %rax, (%r9); ret 计算 val c。.L7(a54, 55): movq $2, %rax; … 计算 val 2。.L2(default): movq $0, %rax; … val 0。voidswitcher(longa,longb,longc,long*dest){longval;switch(a){case50:/* Case A */cb;/* 对应 movq %rsi, %rdx *//* Fall through */case52:/* Case B (与56共享) */valc^15;/* 对应 xorq $15, %rax */break;case53:/* Case C */case54:/* Case D (与55共享) */val2;/* 对应 movq $2, %rax */break;case51:/* Case E (默认项之一) */val0;break;default:val0;}*destval;}总结栏本节深入剖析了 switch语句最高效的实现方式——跳转表揭示了编译器将高级语言多路分支映射到底层硬件的精巧过程。核心是数组跳转编译器将 switch编译为“计算偏移索引→检查边界→间接跳转”的固定模式。跳转表就是一个地址数组间接跳转 (jmp*) 是执行的关键。巧妙的范围平移通过将case值减去最小值化为从0开始的连续索引使得跳转表访问成为可能。同时利用无符号比较一举两得地处理了索引下溢原值太小和上溢原值太大的情况。跳转表编码语义跳转表的内容直接编码了 switch的语义1连续 case连续的表项。2重复 case多个表项指向同一地址。3缺失 case对应表项指向默认块地址。4fall through前一个 case的代码块末尾没有跳出指令。逆向工程心法给定汇编首先找到索引计算sub指令和边界检查cmp/ja这决定了case的原始值范围。然后分析跳转表每个表项对应一个 case值。最后将各个目标代码块.Lx与case行为匹配。练习题3.31是此方法的完整演练。最终启示switch的跳转表实现是编译器优化的典范它通过引入少量静态数据跳转表来换取稳定的、快速的执行时间。理解这一点对于编写高效代码和进行底层调试至关重要。同时这也展示了数据跳转表如何有效地控制程序流。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2431302.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…