riscv下的GCC内联汇编

GCC内联汇编

语法规则

asm volatile(
	汇编指令列表
	∶输出操作数 //非必需
	∶输入操作数 //非必需
	∶可能影响的寄存器或存储器 1/非必需
);
  • Explanation

    • asm 是GCC的关键字,表示内联汇编操作,注 __asm__ 是GCC中asm的宏定义,也可以使用
    • volatile 或者 __volatile__ 是可选的,表示不进行任何优化,否则某些操作可能会被优化掉。
    • 汇编指令列表, 即要嵌入的汇编指令。每条指令应该被双引号括起来作为字符串,两条指令之前必须以 \n 或者 : 作为分隔符,没有添加分隔符的两个字符串将会被合并成为一个字符串。
    • 输出操作数,用来指定当前内联汇编程序的输出操作符列表
    • 输入操作数,用来指定当前内联汇编语句的输入操作符列表
    • 可能影响的寄存器或存储器,用于告知编译器当前内联汇编语句可能会对某些寄存器或内存进行修改,使得编译器在优化时将其因素考虑进去
  • Learn from example

    __asm__  __volatile__(
    	"Instruction_l;\
    	 Instruction 2;\
    	 ...\
    	 Instruction_n;"
    	:[out1]"=r"(valuel), [out2]"=r"(value2), ...[outn]"=r"(valuen)
    	:[inl]"r"(valuel),[in2]"r"(value2),...[inn]"r"(valuen)
    	:"r0","r1",..."rn"
    );
    

输入操作数与输出操作数

GCC 内联汇编语法的"输入操作数"和"输出操作数"部分用来指定当前内联汇编程序的输入和输出操作符列表

  • 遵循的语法如下

    1. 每一个输入或者输出操作符都由以下3部分组成。

      • 方括号[]中的符号名用于将内联汇编程序中使用的操作数(由 %[str] 指定)和此操作符(由 [str] 指定)通过同名"字符"绑定起来。

        除了 %[str] 中明确的符号命名指定外,还可以使用 %数字 的方式进行隐含指定。"数字"从0开始,依次表示输出操作数和输入操作数。假设包含"输出操作数"列表中有2个操作数,"输入操作数"列表中有2个操作数,则汇编程序中 %0 表示第一个输出操作数, %1 表示第二个输出操作数, %2 表示第一个输入操作数, %3 表示第二个输入操作数。

      • 引号中的限制字符串,用于约束此操作数变量的属性,常用的约束如下。

        a)字母"r"表示使用编译器自动分配的寄存器来存储该操作数变量;字母"m"表示使用内存地址来存储该操作数变量。如果同时指明"rm",则编译器自动选择最优方案。

        b)对于"输出操作数"而言,"="代表输出变量用作输出,原来的值会被新值替换;"+"代表输出变量不仅作为输出,而且作为输入。

        **注意:**此约束对不适用于"输入操作数"。

      • 圆括号()中的C/C+变量或者表达式。

      常用的constraints有以下几个:

      • m 内存操作数
      • r 寄存器操作数
      • i 立即数操作数(整数)
      • f 浮点寄存器操作数
      • F 立即数操作数(浮点)
    2. 输出操作符之间需使用逗号分隔。

可能影响的寄存器或存储器

如果内联汇编中的某个指令会更新某些寄存器的值,则必须在 asm中第三个冒号后的"可能影响的寄存器或存储器"中地指定出这些寄存器,通知GCC编译器不再假定之前存入这些寄存器中的值依然合法

  • 指定出这些寄存器由逗号分隔开,每个寄存器由引号包含住::"xl","x2"
  • 注意:对于那些已经由"输入操作数"和"输出操作数"部分约束指定了的变量,由于编译器自动分配寄存器,因此编译器知道哪些寄存器会被更新,则无须指定这部分的寄存器。

Example

int sum;
int add1=100;
int add2=200;

//插入汇编代码调用add汇编指令进行加法操作
__asm__ __volatile__(
		"add %[dest], %[srcl], %[src2]" //使用add指令,一个目标操作数(命名为dest),
								//两个源操作数(分别命名为sre1和src2)
		:[dest]"=r"(sum)                //将add指令的目标操作数dest和C程序中的sum变量绑定。

		:[srcl]"r"(add1),[src2]"r"(add2)//将add指令的源操作数srec1和C程序中的add1变量绑定
								//将源操作数 arc2和add2变量绑定
		//此内联汇编没有指定可能影响的寄存器或存储器,因此省略第三个冒号
);

汇编中调用C/C++函数

**二进制接口(Abstract Binary Interface,ABI):**ABI描述了应用程序和操作系统之间、应用和它的库之间,以及应用的组成部分之间的接口

  • ABI涵盖了如下细节
    1. 数据类型的大小、布局和对齐。
    2. 函数调用约定:例如是所有的参数都通过栈传递,还是部分参数通过寄存器传递;哪个寄存器用于哪个函数参数;通过栈传递的第一个函数参数是最先还是最后推到栈上。
    3. 系统调用的编码和一个应用如何向操作系统进行系统调用。

对于RISC-V汇编程序而言,在汇编程序中调用C/C+语言函数,必须遵照ABI所定义的函数调用规则,即函数参数由寄存器a0 ~a7传递,函数返回由寄存器a0~a1指定.

  • 0
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
GCC内联汇编asm格式是一种将汇编代码嵌入到C或C++源代码中的方法。它允许开发人员直接使用汇编语言来访问底层硬件或执行高性能算法。以下是GCC内联汇编asm格式的详细说明。 基本格式 GCC内联汇编asm格式基本格式如下: ```c asm (assembly code : output operands : input operands : clobbered registers); ``` - assembly code:汇编代码,可以是单行或多行代码。 - output operands:用于存储计算结果的变量,可以有多个,用逗号分隔。输出操作数是可选的,可以省略。 - input operands:用于传递参数的变量,可以有多个,用逗号分隔。输入操作数是必需的。 - clobbered registers:代码执行期间会被修改的寄存器,用于通知编译器。可以有多个,用逗号分隔。clobbered registers是可选的,可以省略。 示例 以下是一个简单的GCC内联汇编asm格式示例,将eax寄存器中的值加1,并将结果存储在eax中。 ```c int value = 10; asm ("addl $1, %%eax" : "=a" (value) : "a" (value)); ``` - "addl $1, %%eax":汇编代码,将eax加1。 - "=a" (value):输出操作数,将eax中的值存储在value变量中。 - "a" (value):输入操作数,将value的值传递给eax。 - 没有clobbered registers。 输出操作数 输出操作数用于将汇编代码的结果存储在变量中。输出操作数有两种类型:普通输出(通道约束)和跨约束输出。 普通输出 普通输出使用“=约束”语法表示,其中约束指定了输出操作数应存储在哪个寄存器或内存位置中。约束可以是以下之一: - "=r"(任意寄存器) - "=m"(任意内存位置) - "=a"(eax寄存器) - "=d"(edx寄存器) - "=q"(eax或edx寄存器) 示例 以下是一个使用普通输出的示例,将eax寄存器中的值加1,并将结果存储在value变量中。 ```c int value; asm ("addl $1, %%eax" : "=a" (value) : "a" (value)); ``` 跨约束输出 跨约束输出是一种将结果存储在多个输出变量中的方法。它使用“+约束”语法表示,其中约束指定了输出操作数应存储在哪个寄存器或内存位置中。多个约束可以用逗号分隔。 示例 以下是一个使用跨约束输出的示例,将eax寄存器中的值加1,并将结果存储在value1和value2变量中。 ```c int value1, value2; asm ("addl $1, %%eax" : "+a" (value1), "=r" (value2)); ``` 输入操作数 输入操作数用于将变量的值传递给汇编代码。输入操作数使用“约束”语法表示,其中约束指定了变量应该存储在哪个寄存器或内存位置中。约束可以是以下之一: - "r"(任意寄存器) - "m"(任意内存位置) - "a"(eax寄存器) - "d"(edx寄存器) - "q"(eax或edx寄存器) 示例 以下是一个使用输入操作数的示例,将value变量的值传递给eax寄存器中。 ```c int value = 10; asm ("movl %0, %%eax" : : "r" (value)); ``` clobbered registers clobbered registers是在汇编代码执行期间会被修改的寄存器列表。它用于通知编译器哪些寄存器应该被保存和恢复。clobbered registers使用“%约束”语法表示,其中约束指定了被修改的寄存器名称。多个寄存器可以用逗号分隔。 示例 以下是一个使用clobbered registers的示例,将eax寄存器中的值加1,并告诉编译器edx寄存器也被修改了。 ```c asm ("addl $1, %%eax" : : "a" (value) : "%edx"); ``` 总结 GCC内联汇编asm格式是一种将汇编代码嵌入到C或C++源代码中的方法。它允许开发人员直接使用汇编语言来访问底层硬件或执行高性能算法。通过输出操作数、输入操作数和clobbered registers,开发人员可以管理汇编代码与C或C++代码之间的数据流和寄存器使用。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值