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

    文章

    4744

    浏览量

    68344
  • 编译器
    +关注

    关注

    1

    文章

    1618

    浏览量

    49047

原文标题:asm goto与JUMP_LABEL

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

收藏 人收藏

    评论

    相关推荐

    嵌入式学习建议

    原理的嵌入式操作系统进行学习。不要一开始就学习几种操作系统,理解了基本原理,实践确有实际需要再学习也不迟。人总是要不断学习的。 ⑨关于汇编语言与C语言的取舍。随着:MCU对
    发表于 10-22 11:41

    什么是嵌入式?一文读懂嵌入式主板

    在现代科技浪潮嵌入式技术已成为支撑各种智能设备和系统运行的核心力量。那么,究竟什么是嵌入式嵌入式系统,顾名思义,是将计算机的硬件和软件嵌入
    的头像 发表于 10-16 10:14 488次阅读

    嵌入式主板是什么意思?嵌入式主板全面解析

    嵌入式主板,通常被称为嵌入式系统的核心组件,是一种用于控制和数据处理的计算机硬件,其设计旨在嵌入特定设备执行专门任务。嵌入式主板如同是设备
    的头像 发表于 09-30 10:05 364次阅读

    一种常用嵌入式开发代码

    使用开源协议:GPL-2.0varch简介varch(we-architecture,意为我们的框架库)是嵌入式C语言常用代码模块库,包含了嵌入式中常用的算法库,数据结构(容器)库,解
    的头像 发表于 09-04 08:06 377次阅读
    一种常用<b class='flag-5'>嵌入式</b>开发<b class='flag-5'>代码</b>库

    嵌入式系统工业4.0网络安全

    CC++在嵌入式系统占主导地位。多年来,实施工业4.0和物联网的组织已经认识所有代码
    的头像 发表于 08-12 21:45 457次阅读
    <b class='flag-5'>嵌入式</b>系统<b class='flag-5'>中</b>工业4.0网络安全

    如何提升嵌入式编程能力?

    :掌握嵌入式系统的基本原理,包括中断、并发、实时操作、低功耗设计等。 3. 实践编程:通过实际编写和测试代码来提高技能。从简单的LED闪烁程序开始,逐步过渡到更复杂的项目,如定时器PWM应用、串口、IIC
    发表于 06-21 10:01

    如何成为一名嵌入式C语言高手?

    。 三、通过实践项目提升技能理论知识是建立在实践基础之上的。选择一些小型的嵌入式项目,例如LED闪烁、温度监测等简单的应用,将所学的C语言知识应用到实际。通过实践,你可以了解如何将
    发表于 04-07 16:03

    如何成为一名嵌入式C语言高手?

    。 三、通过实践项目提升技能理论知识是建立在实践基础之上的。选择一些小型的嵌入式项目,例如LED闪烁、温度监测等简单的应用,将所学的C语言知识应用到实际。通过实践,你可以了解如何将
    发表于 03-25 14:12

    嵌入式fpga是什么意思

    嵌入式FPGA是指将FPGA技术集成嵌入式系统的一种解决方案。嵌入式系统是一种为特定应用而设计的计算机系统,它通常包括处理器、内存、外设
    的头像 发表于 03-15 14:29 1192次阅读

    给大家讲讲嵌入式系统C总线的时序

    C总线在嵌入式系统很常见,今天就来给大家讲讲I²C总线的时序。
    的头像 发表于 02-23 09:47 1568次阅读
    给大家讲讲<b class='flag-5'>嵌入式</b>系统<b class='flag-5'>中</b>I²<b class='flag-5'>C</b>总线的时序

    嵌入式学习-ElfBoard ELF 1开发板-共创官学习笔记分享|将Go程序编译ELF 1开发板

    ElfBoard组建的共创社是嵌入式科技创新与学习实践的前沿阵地,我们有幸见证着每一位共创官积极投身于嵌入式技术的热潮,用实际行动诠释着探索精神。今天就跟各位小伙伴分享一下共创官是怎样将Go
    发表于 02-21 10:22

    嵌入式学习步骤

    硬件组件。 (4).开发固件:编写嵌入式系统的固件,这是嵌入式系统的软件部分。固件负责控制硬件并执行特定任务。 (5).调试和测试:在将嵌入式系统部署实际环境
    发表于 02-02 15:24

    聊一聊嵌入式C语言

    作为一名嵌入式软件开发者,熟练掌握嵌入式C语言对我的日常工作至关重要。
    的头像 发表于 01-22 09:28 523次阅读

    嵌入式自学好书推荐

    嵌入式自学好书推荐 在数字时代的浪潮嵌入式系统一直是数字电子产品的重要组成部分。无论是家用电器、工业控制、汽车电子、医疗保健、军事应用还是物联网,
    发表于 01-11 15:13

    嵌入式C语言高手炼成之内存操作篇

    嵌入式系统的编程,常常要求在特定的内存单元读写内容,汇编有对应的MOV指令,而除C/C++以外的其它编程语言基本没有直接访问绝对地址的能
    的头像 发表于 12-11 17:20 486次阅读