pho*_*ger 5 c c++ gcc sparc inline-assembly
据我所知,在SPARC中,32位整数存储在单个寄存器中,64位整数存储在相邻寄存器对中,偶数寄存器包含高32位,奇数寄存器包含低32位.
我需要编写一些专门的SPARC内联汇编宏(内联汇编函数也可以)处理64位整数双字对,我无法弄清楚如何一般地引用(使用GCC扩展内联汇编)到我的内联装配中两半的一对.虽然我的汇编宏比下面显示的MULTIPLY()宏稍微复杂一些,但乘法示例(如果有效)将演示如何处理64位双字对的两半.谁能告诉我如何修复我的MULTIPLY()宏?
万一重要,我正在......
bash-2.03 $ uname -a
SunOS [...] 5.8 Generic_117350-39 sun4u sparc SUNW,Ultra-80
这是我的简单示例程序(在C中):
#include <stdio.h>
//#include <stdint.h>
#define uint32 unsigned long int
#define uint64 unsigned long long int
#define MULTIPLY(r, a, b) /* (r = a * b) */ \
asm("umul %1, %2, %0;" /* unsigned mul */ \
: /* regs out */ "=h"(r) \
: /* regs in */ "r"(a), "r"(b));
#if 0
: /* clobbers */ "%y" );
#endif
int main(int argc, char** argv)
{
uint64 r;
uint32 a=0xdeadbeef, b=0xc0deba5e;
// loses the top 32 bits of the multiplication because the result is
// truncated at 32 bits which then gets assigned to the 64-bit 'r'...
r = a * b;
printf("u64=u32*u32 ----> r=a*b "
"----> 0x%016llx = 0x%x * 0x%x\n",
r, a, b);
// force promotion of 'a' to uint64 to get 64-bit multiplication
// (could cast either a or b as uint64, which one doesn't matter,
// as one explicit cast causes the other to be promoted as well)...
r = ((uint64)a) * b;
printf("u64=u64*u32 ----> r=((u64)a)*b "
"----> 0x%016llx = 0x%x * 0x%x\n",
r, a, b);
MULTIPLY(r, a, b);
printf("u64=u64*u32 ----> MULTIPLY(r,a,b) "
"----> 0x%016llx = 0x%x * 0x%x\n",
r, a, b);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在编译时gcc-3.2-sun4u/bin/gcc -o mult -mcpu=ultrasparc mult.c,会产生以下输出:
u64=u32*u32 ----> r=a*b ----> 0x00000000d3c7c1c2 = 0xdeadbeef * 0xc0deba5e
u64=u64*u32 ----> r=((u64)a)*b ----> 0xa7c40bfad3c7c1c2 = 0xdeadbeef * 0xc0deba5e
u64=u64*u32 ----> MULTIPLY(r,a,b) ----> 0xd3c7c1c2deadbeef = 0xdeadbeef * 0xc0deba5e
Run Code Online (Sandbox Code Playgroud)
我查看-S -fverbose-asm了gcc 的输出,它正在做一些奇怪的结果寄存器移位(甚至是)并写入相邻的奇数寄存器.我的问题是我不知道如何在扩展的asm语法中一般引用相邻的奇数寄存器.我想也许'h'asm约束"=h"(r)可能与它有关,但我找不到任何如何使用它的例子.
首先,非常感谢 Chris Dodd、torek 和 gbulmer 的努力和帮助。我设法弄清楚如何通过我在这里找到的一些评论来做到这一点,部分复制(并对形式但不内容进行了稍微编辑)如下:
主题:RFE:“h”和“U”asm 约束以及“H”和“L”修饰符。
[...]某些 v8+ ABI 内联汇编的以下两个约束(引自 gcc.info):
SPARC-V8+ 架构的“h”64 位全局或输出寄存器。
'U' 偶数寄存器
“U”需要为 ldd/std 分配寄存器(它为 uint64_t 分配偶数 + 奇数对)。例如:Run Code Online (Sandbox Code Playgroud) 无论有或没有“U”作为约束,都可以在模板中使用“H”和“L”作为修饰符来获取用于 64 位值的一对高寄存器和低寄存器。“h”约束分配一个寄存器,根据 v8+ ABI,人们可以安全地使用所有 64 位(仅限全局或输出寄存器)。以下(人工)示例演示了“h”约束以及“H”和“L”修饰符:void atomic64_set(volatile uint64_t *p, uint64_t v) { asm volatile ( "std %1, %0" : "=m"(*p) : "U"(v) ); }Run Code Online (Sandbox Code Playgroud) 免责声明:这些示例是当场编写的,对于早期攻击和类似问题可能不正确。void ex_store64(uint64_t *p, uint64_t v) { register int tmp; // Don't say uint64_t or GCC thinks we want 2 regs asm volatile ( "sllx %H2,32,%1 \n\t" // tmp = HI32(v) << 32 "or %1,%L2,%1 \n\t" // tmp |= LO32(v) "stx %0, %1" // store 64-bit tmp : "=m"(*p), "=&h"(tmp) : "r"(v)); }
——保罗
基于此,我能够从问题陈述中找出如何重写我自己的“MULTIPLY”宏:
#define MULTIPLY(r, a, b) /* r = a * b */\
asm("umul %1, %2, %L0;" /* umul a,b,r */\
"srlx %L0, 32, %H0;" \
: /* regs out */ "=r"(r) \
: /* regs in */ "r"(a), "r"(b));
/* re: clobbbers "none": I tried specifying :"%y"
* in various ways but GCC kept telling me
* there was no y, %y, or %%y register. */
Run Code Online (Sandbox Code Playgroud)
我现在的结果是:
u64=u32*u32 ----> r=a*b ----> 0x00000000d3c7c1c2 = 0xdeadbeef * 0xc0deba5e
u64=u64*u32 ----> r=((u64)a)*b ----> 0xa7c40bfad3c7c1c2 = 0xdeadbeef * 0xc0deba5e
u64=u64*u32 ----> MULTIPLY(r,a,b) ----> 0xa7c40bfad3c7c1c2 = 0xdeadbeef * 0xc0deba5e
Run Code Online (Sandbox Code Playgroud)