【源码阅读】预备知识总结:GNU内联汇编

背景

Linux内核代码、JVM源码中有很多关于内联汇编的操作,如果想阅读相关代码,比如JVM的Code Stub Generator,学习内联汇编是不可或缺的一环,在此进行总结一番。

汇编语法

语法特性intelAT&T/UNIX
寄存器命名eax%%eax(需要加’%%'前缀)
操作数顺序op ,op ,
立即数格式123, _C_static_variable$123, $_C_static_variable(添加’$'前缀)
操作数大小指定mov bx, axmovw %ax,%bx(添加b(byte)、w(word)、l(longword)后缀)
引用内存[base + index*scale + immed32]immed32(base,index,scale)
引用变量值_var(加’_'前缀)$_var(加’$_'前缀)
引用变量地址[_var]_var
引用寄存器地址[eax](%eax)
引用var变量为基址的偏移[eax + _var]_var(%eax)
引用int数组arr的某个元素[eax * 4 + _arr]_arr(, %eax, 4)

内联语法

为什么需要内联?能获得可预知大小的代码

asm <关键字> (汇编代码
            : 输出操作数
            : 输入操作数
            : Clobbers)
asm <关键字> (汇编代码
            :
            : 输入操作数
            : Clobbers
            : Goto C Labels)
  • 关键字

输入操作数、输出操作数、跳转Label列表的操作数总数不能超过30个

volatile:阻止代码优化

inline:内联代码,将会对代码进行压缩

goto:告知编译器代码中将会对列表中的某个Label进行跳转

  • 汇编代码
    GAS汇编

  • 输出操作数
    用于接收汇编代码计算结果

  • 输入操作数
    输入变量值,被汇编代码引用计算

  • Clobbers
    用于告知编译器汇编代码隐式的副作用

  • Goto C Label
    C语言定义的Label列表

关键字

  • asm或者__asm__
    定义一段内联汇编代码。

如果使用ANSI C编写代码,必须使用__asm__关键字

  • volatile或者__volatile__

参考《汇编语言程序设计》p296

在一般的C或者C++程序中,编译器通常会尝试通过下面方式来对代码进行优化,以提高程序性能:
1、消除不使用的函数
2、在不同时使用的值之间共享寄存器
3、重新编排代码

volatile会抑制GCC的上述的代码优化。

如果我们修改了不在输入、输出操作数列表中的内存,我们必须添加在asm后添加volatile关键字。

assembler template

1、存在多行汇编指令时,使用\n\t分隔,例如:

__asm__ ("movl %eax, %ebx\n\t"
        "movl %eax, %edx")

输出操作数

<[可选名称]> 约束 (C表达式)
  • 可选名称
    为操作数指定一个名称,可以通过%[名称]进行引用,如果不指定,则通过序号进行访问
__asm__ __volatile__ ("movw %%dx,%%ax\n\t"
    "movw %4,%%dx\n\t"
    "movl %%eax,%[gate_addr_1]\n\t"
    "movl %%edx,%1"
    :[gate_addr_1]"=m" (*((long *) (gate_addr))),
     "=m" (*(1+(long *) (gate_addr))),
     "=&a" (__d0),
     "=&d" (__d1)
    :"i" ((short) (0x8000+(14<<13)+(0<<8))),
     "3" ((char *) (addr)),"2" (__KERNEL_CS << 16),
     "d" (1)
     );

其中定义了个gate_addr_1的输出操作数,在汇编中可以通过%[gate_addr_1]进行引用

  • 约束
    必须以’+‘或者’='作为前缀
    ‘+’:可读写,操作数会在输入操作数完成读取之前进行写入;不能被输入操作数绑定
__asm__ __volatile__ ("movw %%dx,%%ax\n\t"
    "movw %4,%%dx\n\t"
    "movl %%eax,%[gate_addr_1]\n\t"
    "movl %%edx,%1"
    :[gate_addr_1]"=m" (*((long *) (gate_addr))),
     "=m" (*(1+(long *) (gate_addr))),
     "+a" (__d0),
     "+d" (__d1)
    :"i" ((short) (0x8000+(14<<13)+(0<<8))),
     "3" ((char *) (addr)),"2" (__KERNEL_CS << 16),
     "d" (1)
     );

输出操作数中,ax和dx寄存器使用’+‘进行约束,由于在输入操作数中又进行了操作数的绑定,这会报错。这是因为当使用’+'约束时,输入输出操作数是绑定在同一个C变量上的,当尝试进行绑定时,就发生了冲突

‘=’:只写、覆盖

  • C表达式
    C变量,必须是一个左操作数

1、’&‘约束表示寄存器不能与输入操作数重复;但可以进行操作数绑定
2、’+‘约束表示变量可能会被重写
3、’='约束表示可以进行读写,和输入操作数关联输出操作数语义类似

输入操作数

模版:

<[可选名称]> 约束 (C表达式)
  • 可选名称
    为操作数指定一个名称,可以通过%[名称]进行引用,如果不指定,则通过序号进行访问

  • 约束
    不以’+’(表示变量会被重写)或者’=’(表示)开头

  • C表达式
    右值表达式

1、不要修改只作为输入操作数的内容。一般通过将输入操作数绑定到输出操作数上
2、有且只有输入操作数可以在约束中使用数字,该数字必须是输出操作数的序号,以表示对该输出操作数的引用。(也可通过可选名称对输出操作数进行引用)

Clobbered Registers

示例:

"cc","r1","r2","cc","memory"

1、不能跟输入和输出操作数重复
2、新版GCC(10+)不支持栈寄存器,这是因为编译器要求栈指针在汇编指令执行前和执行后必须保持一致
3、"cc"表示条件寄存器的修改
4、"memory"告知编译器汇编代码会进行除了输入输出操作数之外的内存的读写,比如访问入参变量的值作为地址的内存
6、Clobber不会阻止通过指令进行的寄存器的预读,如有需要,必须通过处理器的屏障指令进行阻止。

跳转label

asm goto (汇编代码
        :
        : 输入操作数
        : Clobbers
        : Goto C Labels)

1、不能包含输出操作数
2、如果汇编代码发生修改,需要通过"memory" Clobber刷新内存
3、asm goto本身包含volatile的语义
4、引用标号:%l[<LABEL名称>]

    __asm__ goto (
        "cmp $1,$1\n\t"
        "jz %l[LABEL]"
        :
        :
        :
        : LABEL
    );
    ...
    LABEL:
    printf("jmp");

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
FreeRTOS是一个开源的实时操作系统,用于嵌入式系统中。ELF是一种可执行文件格式,用于存储和传输可执行程序和库。 在FreeRTOS中,程序的编译后会生成一个可执行文件,通常是ELF格式。如果我们想对这个可执行文件进行反汇编,我们可以使用相应的工具。 ELF反汇编是将二进制代码转换回汇编语言的过程。它可以帮助我们理解程序的结构和执行流程,并进行调试和优化。 可以使用一些工具进行ELF反汇编,例如GNU工具链中的objdump命令。objdump可以读取ELF格式的文件,并将其转换为可读的汇编代码。 具体来说,如果我们想对FreeRTOS的ELF文件进行反汇编,我们可以使用以下命令: ``` objdump -d [可执行文件路径] ``` 这将生成一个包含汇编代码的文件,我们可以在其中查看程序的反汇编结果。 在进行ELF反汇编时,我们可以观察指令的地址、指令的类型以及操作数等信息。通过分析反汇编结果,我们可以更好地理解程序的运行逻辑,并发现隐藏的问题或优化的机会。 然而,需要注意的是,反汇编并不总是能够完全还原原始源代码。因此,在进行ELF反汇编时,应该结合其他调试和性能分析工具,以全面理解和优化代码。 总之,ELF反汇编是一个有用的工具,可以帮助我们理解和优化FreeRTOS中的程序。通过分析反汇编结果,我们可以更好地理解程序的执行流程和结构,从而提高嵌入式系统的性能和可靠性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木子的木木

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值