0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

嵌入式汇编中go to到c代码label最简单的用法

Linux阅码场 来源:CSDN 作者:dog250 2021-04-04 17:18 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

越来越多的工作现如今都交给了编译器,甚至连动态代码修改的数据组织这种事都交给了编译器。gcc提供了一个特性用于嵌入式汇编,那就是asm goto,其实这个特性没有什么神秘之处,就是在嵌入式汇编中go to到c代码的label,其最简单的用法如下(来自gcc的文档):

d0f90b8c-8cdd-11eb-8b86-12bb97331649.png

asm goto其实就是在outputs,inputs,registers-modified之外提供了嵌入式汇编的第四个“:”,后面可以跟一系列的c语言的label,然后你可以在嵌入式汇编中go to到这些label中一个。然而使用asm goto可以巧妙地将“一个大家都能想到的点子”规范化,就是说你只需要调用一个统一的接口--一个宏,编译器就将你想实现的东西给实现了,要不然代码写起来会很麻烦,这点上,编译器不嫌麻烦。这一个大家都能想出的点子的由来还得从内核的效率说起。

以下的代码来自lwn的《Jump label》:

d11a53be-8cdd-11eb-8b86-12bb97331649.png

即使有了unlikey优化,既然有if判断,cpu的分支预测就有可能失败,再者do_trace在代码上离if这么近,即使编译器再聪明,二进制代码的do_trace也不会离前面的代码太远的,这样由于局部性原理和cpu的预取机制,do_trace的代码很有可能就被预取入了cpu的cache,就算我们从来不打算trace代码也是如此。

我们需要的是如果不开启trace,那么do_trace永远不被欲取或者被预测,唯一的办法就是去掉if判断,永远不调用goto语句,像下面这样:

d16ccc02-8cdd-11eb-8b86-12bb97331649.png

在运行时修改载入内存的二进制代码就是我们大家都能想到的点子,就是说在运行的时候当我们知道trace_foo_enabled在某一时刻被设置为0的时候,我们动态的将二进制代码修改掉,将if代码段去掉,这样一个分支预测就不存在了,而且trace_foo_enabled这一个变量也不需要再被访问了(该变量在内存中,访问它肯定会涉及load/flush cache的动作,为了一个很可能没有用的变量操作cache很不值)。提前要说的是,我们可以使用这种方式去掉所有的分支预测,然而这并不可取,因为程序是动态运行的,很多用于判断的变量值都是根据程序的执行瞬息万变,正是这种根据判断结果采取不同动作的机制给与了程序灵活性,如果每当我们确定一个值时就修改二进制代码取消分支预测的话,其本身的开销将会远远大于分支预测的开销,更重要的是,紧接着那个值又变化了,我们不得不再次修改二进制代码,这期间要访问那个变量好几次。所以,只有在我们确定不经常变化的变量的判断上才能用这种方式取消分支预测,而像trace与否的判断正好符合我们的需求。

gcc编译器提供了asm goto的机制来满足我们的需求,使得我们可以在asm goto的基础上构建出一个叫做jump label的东西。下面的代码段说明了jump label的用法和原理:

d1e01e96-8cdd-11eb-8b86-12bb97331649.png

标号0仅仅执行一个nop,不涉及cache,后面的pushsection保存现有的section,很多情况下当前的section就是text,然后定义一个“表”,表中有两个元素:0b和trace#NUM,其实就是两个标号,在asm goto机制中,标号还可以更多,它们在嵌入式汇编的最后一个“:”后面依次排布。这些标号就是供选择的标号,执行流将跳入其中的一个标号处,具体跳到哪一个就看当前的二进制代码被修改成了“跳到哪一个”,因此asm goto为我们做的仅仅是提供一个地方(一个“:”)供我们将label传入,保存了一系列的表还是需要我们的c代码逻辑--jump label实现,这些表(其实就是一系列的三元组)方便我们根据这些表来修改运行中的二进制代码,最终修改二进制代码还是要由我们自己写代码完成的。

有了这个asm goto以及我们jump label代码的支持,内核对于是否trace这种小事就再也不用愁了(使用中的kernel一般是不用trace的,只有在出了问题以后或者调试内核时才使用trace,因此在主代码中加入“是否trace”的判断实在是一种沉重的负担),如果对于某一个函数不需要trace,内核只需要执行一个操作将asm goto附近的代码改掉即可,比如改称下面这样:

d1fcdf54-8cdd-11eb-8b86-12bb97331649.png

如果需要trace,那么就改成:

d227dd30-8cdd-11eb-8b86-12bb97331649.png

这一切在kernel中的用法如下:

d246edba-8cdd-11eb-8b86-12bb97331649.png

第一行的“1”是一个标号,该标号后的代码执行的内容就是nop-第二行,第三行重新开始了一个section,这样的意义很大,下面的三元组:[instruction address] [jump target] [tracepoint key]的二进制代码就不会紧接着标号1(nop)了,这个三元组就是jump label机制的核心,指示了所有可能跳转到的标号,这里的技巧在于标号1,标号1也作为一个合法的可能跳转到的标号存在,和标号label是并列的,由于pushsection和popsection的存在,上面的代码汇编结果看起来是下面这样:

d262c2c4-8cdd-11eb-8b86-12bb97331649.png

如果启用了trace,那么只需要将标号1修改成标号label就可以了:

d2b347f8-8cdd-11eb-8b86-12bb97331649.png

内核之所以能够找到需要修改代码的地址,就是借助于上面说的那个三元组(instruction address,jump target,tracepoint key),其中instruction address就是这个地址,在linux的JUMP LABEL机制中,它固定为标号1,也就是nop的标号,如果不启用trace,那么直接执行nop,如果启用了trace,那么将nop修改为jmp label即可,如果后来又禁用了trace,只需将它再次修改成三元组中的标号1即可,这一切过程中,三元组本身是不会改变的。注意,三元组中的tracepoint key在jump label机制中并没有什么实质的意义,它仅仅是为了组织kernel中“是否trace”变量用的,所有的“是否trace”变量组织成一个链表,链表的每一个节点下面挂着另一个子链表,该子链表中元素是所有使用这个“是否trace”变量的代码环境,包括代码的地址,标号的地址等。

下面看一下kernel对于JUMP_LABEL的实现框架。首先看一下三元组的数据结构:

d2f035e6-8cdd-11eb-8b86-12bb97331649.png

其次一个比较重要的数据结构是一个key节点,表示一个“是否trace”的变量:

d33b7420-8cdd-11eb-8b86-12bb97331649.png

启用一个trace意味着需要将一个key(类似于trace_foo_enabled)设置为1,然后修改所有判断该key的代码附近的二进制代码:

d3842de6-8cdd-11eb-8b86-12bb97331649.png

d3b8bc78-8cdd-11eb-8b86-12bb97331649.png

以上就是使用asm goto实现的jump label,在2.6.37内核中被引入。

附:.section以及.previous

在汇编语言中使用.section和.previous指令可以将它们之间的代码编译到不同的section中,也就是不紧接着.section上面的代码。linux kernel中的异常处理就是用这两个伪指令实现的,定义了一个叫做fix的section和一个叫做ex_table的section,可能出现exception的代码用一个标号表示,ex_table中保存了一些二元组(出现异常代码的标号,异常处理程序的标号),异常处理程序在fix这个section中,这样虽然代码看起来是下面这样:

d3f8c854-8cdd-11eb-8b86-12bb97331649.png

然而编译器会将fix和ex_table放到离text很远的地方的,这样cpu预取时就不会将fix或者ex_table的代码预取到执行cache了,只有在发生异常的时候才会使用fix和ex_table,而发生异常毕竟是一种罕见现象,这就是一种优化。

原文标题:asm goto与JUMP_LABEL

文章出处:【微信公众号:Linuxer】欢迎添加关注!文章转载请注明出处。

责任编辑:haq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 代码
    +关注

    关注

    30

    文章

    4941

    浏览量

    73149
  • 编译器
    +关注

    关注

    1

    文章

    1669

    浏览量

    51082

原文标题:asm goto与JUMP_LABEL

文章出处:【微信号:LinuxDev,微信公众号:Linux阅码场】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    ARM嵌入式这样学

    软件,嵌入式应用软件。大部分的嵌入式软件都寄宿在ARM内核的芯片上,三星,飞利浦等等都有ARM内核的IC,做计算机软件的人,很容易的就转做嵌入式软件,但是要做嵌入式驱动软件的话,就有点
    发表于 12-04 07:48

    CW32嵌入式软件开发的必备知识

    嵌入式系统中最常用的编程语言,因为它们提供了直接访问硬件的能力,并且代码执行效率高。 了解汇编语言,用于编写底层驱动、中断处理程序以及性能要求极高的代码段。 对其他编程语言如Pytho
    发表于 11-28 07:48

    C语言在嵌入式开发的应用

    C 语言在汽车电子控制系统开发的主导地位。 2、设备驱动程序 设备驱动程序是嵌入式系统连接硬件和软件的桥梁,它负责实现嵌入式系统与
    发表于 11-21 08:09

    嵌入式C/C++回归测试四大最佳实践(附自动化测试工具TESSY使用教程)

    嵌入式开发,一次微小的代码改动都可能引发“蝴蝶效应”,如何守护系统的稳健?推荐专业的自动化测试工具#TESSY,源自戴姆勒-奔驰,是嵌入式C
    的头像 发表于 10-31 14:21 184次阅读
    <b class='flag-5'>嵌入式</b><b class='flag-5'>C</b>/<b class='flag-5'>C</b>++回归测试四大最佳实践(附自动化测试工具TESSY使用教程)

    嵌入式需要掌握哪些核心技能?

    : 1)C语言与底层编程 核心地位:C语言是嵌入式开发的基石,需精通指针操作、内存管理、位运算,直接操控硬件资源。 延伸技能:C++用于复杂项目架构设计,
    发表于 10-21 16:25

    嵌入式达到什么水平才能就业?

    工具定位问题具备嵌入式软件模块化设计能力:能按功能划分代码模块,编写规范的头文件与源文件,实现模块间低耦合调用会使用Git 进行版本管理:能提交代码、解决冲突、回滚版本,熟悉敏捷开发流程
    发表于 09-15 10:20

    嵌入式从入门进阶,怎么学?

    嵌入式从入门进阶,怎么学? 嵌入式学习的核心是 “软硬结合的技术壁垒”,科学分层才能高效突破。以下是从入门高阶的精简路线,帮你避开弯路: 1、基础奠基层:构建技术底座
    发表于 09-02 09:44

    入行嵌入式应该怎么准备?

    知识: 一、C/C++编程C/C++是嵌入式系统开发中最常用的编程语言。熟练掌握C/
    发表于 08-06 10:34

    嵌入式系统,FLASH 的程序代码必须搬到 RAM 运行吗?

    嵌入式系统里,FLASH 的程序代码并非必须搬到 RAM 运行,这得由硬件配置、实际性能需求和应用场景共同决定。就像很多低端单片机,无论是依赖片内 Flash 还是外挂的 SPI
    的头像 发表于 08-06 10:19 1138次阅读
    <b class='flag-5'>嵌入式</b>系统<b class='flag-5'>中</b>,FLASH <b class='flag-5'>中</b>的程序<b class='flag-5'>代码</b>必须搬到 RAM <b class='flag-5'>中</b>运行吗?

    Linux嵌入式和单片机嵌入式的区别?

    : 单片机嵌入式 :开发环境相对简单,通常使用C语言或汇编语言进行编程,开发工具包括Keil、IAR等。 Linux嵌入式 :开发环境较
    发表于 06-20 09:46

    Python在嵌入式系统的应用场景

    你想把你的职业生涯提升到一个新的水平?Python在嵌入式系统中正在成为一股不可缺少的新力量。尽管传统上嵌入式开发更多地依赖于CC++语言,Python的优势在于其简洁的语法、丰富的
    的头像 发表于 03-19 14:10 1191次阅读

    嵌入式系统代码优化与压缩技术

    在当今数字化时代,嵌入式系统广泛应用于各个领域,从智能家居设备工业控制系统,从汽车电子可穿戴设备,它们无处不在。而在嵌入式系统开发
    发表于 02-26 15:00

    如何提高嵌入式代码质量?

    并提升代码质量。 遵循良好的软件工程实践 良好的软件工程实践是提高代码质量的基础,特别是在嵌入式系统更为重要。以下是几个关键点: 1. 模块化设计:将系统分解为独立的模块,每
    发表于 01-15 10:48

    新手怎么学嵌入式?

    基本的概念。嵌入式系统是一种将计算机技术嵌入特定设备的系统,它通常具有特定的功能和有限的资源。你需要学习一些计算机基础知识,如数据结构、操作系统、计算机组成原理等。这些知识将帮助你
    发表于 12-12 10:51

    什么是嵌入式人工智能

    嵌入式人工智能是指将人工智能技术应用于嵌入式系统的一种技术。嵌入式系统是嵌入其他设备或系统
    的头像 发表于 12-11 09:23 1519次阅读
    什么是<b class='flag-5'>嵌入式</b>人工智能