GNU内联汇编之占位符的使用

本文详细介绍了GNU内联汇编中的占位符,包括序号占位符和名称占位符的使用。序号占位符按照Input/Output操作表达式的顺序从%0到%9对应不同的表达式,而名称占位符则通过变量名来标识,提高了代码可读性。文中通过实例解析了如何在内联汇编中应用这些占位符。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

From: 杂项

用心感受,用心感受 - ..

一、GNU内联汇编中常用修饰符一览

修饰符输入输出含义
=O表示此Output操作表达式是只写的
+O表示此Output操作表达式是可读可写的
&O表示此Output操作表达式独占为其指定的寄存器
%I表示此Input操作表达式中的C/C++表达式可以与下一个Input操作表达式中的C/C++表达式互换

什么是占位符?

每一个占位符对应一个Input/Output操作表达式;
带C/C++表达式的内联汇编中有两种占位符,分别是序号占位符和名称占位符;

a.序号占位符

GCC规定一个内联汇编语句中最多只能有10个Input/Output操作表达式,这些操作表达式按照他们被列出来的顺序依次赋予编号0到9;对于占位符中的数字而言,与这些编号是对应的;比如:占位符%0对应编号为0的操作表达式,占位符%1对应编号为1的操作表达式,依次类推。
由于占位符前面要有一个百分号%,为了去边占位符与寄存器,GCC规定:在带有C/C++表达式的内联汇编语句的指令列表里列出的寄存器名称前面必须使用两个百分号(%%),一区别于占位符语法。
GCC对占位符进行编译的时候,会将每一个占位符替换为对应的Input/Output操作表达式所指定的寄存器/内存/立即数。
用一句话描述就是: 序号占位符就是前面描述的%0、%1、%2、%3、%4、%5、%6、%7、%8、%9`,其中,每一个占位符对应一个Input/Output的C/C++表达式;

2.名称占位符

由于GCC中限制这种占位符的个数最多只能由这10个,这也就限制了Input/Output操作表达式中C/C++表达式的数量做多只能有10个;如果需要的C/C++表达式的数量超过10个,那么,这些需要占位符就不够用了;
GCC内联汇编提供了名称占位符来解决这个问题;即:使用一个名字字符串与一个C/C++表达式对应;这个名字字符串就称为名称占位符;而这个名字通常使用与C/C++表达式中的变量完全相同的名字;
使用名字占位符时,内联汇编的Input/Output操作表达式中的C/C++表达式的格式如下:
[name] “constraint”(变量)
此时,指令列表中的占位符的书写格式如下:
%[name]
这个格式等价于序号占位符中的%0,%1,$2等等;
使用名称占位符时,一个name对应一个变量;
例如:
asm(“imull %[value1],%[value2]”
:[value2] “=r”(data2)
:[value1] “r”(data1),”0”(data2));
此例中,名称占位符value1就对应变量data1,名称占位符value2对应变量data2;GCC编译的时候,同样会把这两个占位符分别替换成对应的变量所使用的寄存器/内存地址/立即数;而且也增强了代码的可读性;
这个例子,使用序号占位符的写法如下:
asm(“imull %1,%0”
:”=r”(data2)
:”r”(data1),”0”(data2));

二、占位符的例子描述

最近在一段读地址的函数遇到了使用占位符的DEMO!

static __inline__  test(uint64_t phys, int cca)
{
        uint64_t value = 0;
        __asm__ __volatile__(".set push\n"  /*压栈操作*/
        ".set noreorder\n"                  /*默认汇编器处于reorder模式下,切换到noreorder模式<指令的执行顺序不会被优化和改变>*/
        ".set mips64\n"                     /*设置指令集 mips64*/
        "dli    $8, " STR(NLH_XKPHYS) "\n" /*加载64位常数*/
        "or $8, $8, %2\n"                 /*$8 = $8 | %2*/
        "daddu $8, $8, %1\n"             /*$8 = $8 + %1*/
        "lw %0, 0($8) \n" 				/*%0 = *((long long *))$8*/ /*载入并将高位补0*/
        ".set pop\n"                    /*弹栈操作*/
        :"=r"(value)
        :"r"(phys & 0xfffffffffcULL),"r"((uint64_t) cca << 59)
        :"$8");
        return value;
}

上述代码怎么翻译呢?

$8 = $8 | %2 <==> $8 = $8  |   cca << 59
$8 = $8 + %1  <==> 0x9000000000000000 +  phys & 0xfffffffffcULL
%0 = *((long long *))$8 <==> 	value = *((long long *)$8)

也就是占位符%0 <==> value,占位符%1 <==> phys & 0xfffffffffcULL,占位符%2<==> cca << 59

By: Keven - 点滴积累

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值