gcc内联汇编

基本格式

asm asm-qualifiers ( AssemblerTemplate 
                 : OutputOperands 
                 [ : InputOperands
                 [ : Clobbers ] ])

对于ARMCC,使用__asm而不是asm

ARM Compiler User Guide Version 6.6

asm-qualfiers

asm-qualifiers说明
volatile提示编译器不要对汇编代码进行优化(例如移动代码位置,甚至直接忽略掉代码)
inline提示编译器估算汇编代码长度的方式(很少用)
goto提示编译器此内联汇编可能会执行跳转到某些标号的操作(很少用)。

AssemeblerTemplate

这部分是传递给汇编器的汇编代码编写部分,可以使用任何合法的汇编指令。汇编指令的操作数可以设置为一般的寄存器、立即数、内存地址等,也可以设置为占位符,由后续OutputOperands以及InputOperands来决定。

%(百分号)被用作特殊转义字符,因此%%表示%{}|被用作特殊字符,因此%{表示{%}表示}%|表示|

在如下例子中,使用了寄存器eax,以及占位符%0, %1来作为操作数。

asm volatile (
		"movl %%eax, %0\n\t"
		"addl %0, %1"
		: "=r" (variable1)
		: "r" (variable2)
		: "eax"
);

"=r" (variable1)指定输出操作数,其表示第一个占位符变量%0为C语言变量variable1, 并且在汇编中使用寄存器(r)的方式存储,且变量是只写的(r之前的=,只写表示不关心变量之间的值)。变量对应的占位符的名称可以自定义,例如[v_name] "=r (variable)"就指定变量variable对应的占位符名称为%[v_name],没有指定占位符名称的变量其占位符名称按照变量定义顺序依次为%0,%1,%2...

"r" (variable2)指定输入操作数,其表示第二个占位符变量%1为C语言变量variable2, 并且在汇编中使用寄存器(r)的方式存储,变量是只读的(读写变量需要在输出操作数中指定)。变量对应的占位符的名称可以自定义,例如[v_name] "=r (variable)"就指定变量variable对应的占位符名称为%[v_name],没有指定占位符名称的变量(从第一个变量开始,不分输出和输入操作数),其占位符名称按照变量定义顺序依次为%0,%1,%2...

"eax"则表示汇编代码内部会修改eax寄存器

OutputOperands

输出操作数位于AssemeblerTemplate后,使用:(分号)隔开,可以为空,也可以指定多个输出操作数,每一个操作数由如下三个部分来定义(第一部分asmSymbolicName,也就是上文所提到的占位符变量名称可以省略),多个输出操作数之间通过,逗号隔开。

[asmSymbolicName] constraint (cvariablename)

如下例子定义了三个输出操作数,对应c语言变量variable1, variable3以及variable4

asm volatile (
		"movl %%eax, %0\n\t"
		"addl %0, %1"
		: [v1] "=r" (variable1), "+r" (variable3), [v4] "=r" (variable4)
		: "r" (variable2)
		: "eax"
);

constraint主要由两部分,第一部分表示读写操作限制,第二部分为变量存储的方式限制,读写限制只能指定一种,存储限制可以指定多种让编译器选择最合适的方式,例如"=rmi"

读写限制说明
+该变量即被读取也被写入
=该变量仅被写入(即不关心变量之前的值)
存储限制说明
r使用寄存器保存
m使用内存保存
i使用立即数保存

InputOperands

InputOerands位于OutputOperands之后,使用:(分号)隔开,其格式同OutputOperands一致,唯一的区别是InputOerands变量默认是只读的,并且无法使用读写限制符号进行控制(即constraint中无法使用+=),因此同时需要读写的变量只能写在OutputOperands

[asmSymbolicName] constraint (cvariablename)
asm volatile (
		"movl %%eax, %0\n\t"
		"addl %0, %1"
		: [v1] "=r" (variable1), "+r" (variable3), [v4] "=r" (variable4)
		: "r" (variable2)
		: "eax"
);

Clobbers

Clobbers描述汇编代码对寄存器和内存的修改情况(除开InputOperandsOutputOperands中指定的变量之外),位于InputOerands之后,使用:分号隔开, 如果需要修改多个寄存器,使用,隔开,通过指针修改内存则需要加入"memory"

: ”eax“, "ebx", "memory" 

例子

使用内联汇编实现字节序转换

// x86
#define BSWAP4(des, src) asm ( "movl %1, %0\n"\
                               "bswap %0" \
                               : "=r"(des) \
                               : "r"(src))
// arm
#define BSWAP4(des, src) asm ("rev %0, %1" \
                        : "=r"(des) \
                        : "r"(src))

参考 Extended Asm (Using the GNU Compiler Collection (GCC))

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
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++代码之间的数据流和寄存器使用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值