- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我在下面包含 Sparc 程序集的 C 代码中遇到问题。代码在 Debian 9.0 Sparc64 上编译运行。它做一个简单的求和并打印这个总和的结果等于nLoop
.
问题是对于大于 1e+9 的初始迭代次数,最后的总和系统地等于 1410065408 :我不明白为什么,因为我明确地输入了 unsigned long long int
输入 sum
变量等等 sum
可以在[0, +18,446,744,073,709,551,615]
范围。
例如,对于 nLoop = 1e+9
, 我期待 sum
等于1e+9
.
问题是否来自无法处理 64 位变量(输入或输出)的包含的 Assembly Sparc 代码?
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
int i;
// Init sum
unsigned long long int sum = 0ULL;
// Number of iterations
unsigned long long int nLoop = 10000000000ULL;
// Loop with Sparc assembly into C source
asm volatile ("clr %%g1\n\t"
"clr %%g2\n\t"
"mov %1, %%g1\n" // %1 = input parameter
"loop:\n\t"
"add %%g2, 1, %%g2\n\t"
"subcc %%g1, 1, %%g1\n\t"
"bne loop\n\t"
"nop\n\t"
"mov %%g2, %0\n" // %0 = output parameter
: "=r" (sum) // output
: "r" (nLoop) // input
: "g1", "g2"); // clobbers
// Print results
printf("Sum = %llu\n", sum);
return 0;
}
如何解决这个范围问题并允许在 Sparc 汇编代码中使用 64 位变量?
PS:我尝试用 gcc -m64 编译,问题依旧。
应@zwol 的要求,下面是生成的输出 Assembly Sparc 代码:gcc -O2 -m64 -S loop.c -o loop.s
.file "loop.c"
.section ".text"
.section .rodata.str1.8,"aMS",@progbits,1
.align 8
.LC0:
.asciz "Sum = %llu\n"
.section .text.startup,"ax",@progbits
.align 4
.global main
.type main, #function
.proc 04
main:
.register %g2, #scratch
save %sp, -176, %sp
sethi %hi(_GLOBAL_OFFSET_TABLE_-4), %l7
call __sparc_get_pc_thunk.l7
add %l7, %lo(_GLOBAL_OFFSET_TABLE_+4), %l7
sethi %hi(9764864), %o1
or %o1, 761, %o1
sllx %o1, 10, %o1
#APP
! 13 "loop.c" 1
clr %g1
clr %g2
mov %o1, %g1
loop:
add %g2, 1, %g2
subcc %g1, 1, %g1
bne loop
nop
mov %g2, %o1
! 0 "" 2
#NO_APP
mov 0, %i0
sethi %gdop_hix22(.LC0), %o0
xor %o0, %gdop_lox10(.LC0), %o0
call printf, 0
ldx [%l7 + %o0], %o0, %gdop(.LC0)
return %i7+8
nop
.size main, .-main
.ident "GCC: (Debian 7.3.0-15) 7.3.0"
.section .text.__sparc_get_pc_thunk.l7,"axG",@progbits,__sparc_get_pc_thunk.l7,comdat
.align 4
.weak __sparc_get_pc_thunk.l7
.hidden __sparc_get_pc_thunk.l7
.type __sparc_get_pc_thunk.l7, #function
.proc 020
__sparc_get_pc_thunk.l7:
jmp %o7+8
add %o7, %l7, %l7
.section .note.GNU-stack,"",@progbits
更新 2:
根据@Martin Rosenau 的建议,我做了以下修改:
loop:
add %g2, 1, %g2
subcc %g1, 1, %g1
bpne %icc, loop
bpne %xcc, loop
nop
mov %g2, %o1
但是在编译时,我得到:
Error: Unknown opcode: `bpne'
这个编译错误可能是什么原因?
最佳答案
subcc %%g1, 1, %%g1
bne loop
你的问题是 bne
指令:
与 x86-64 CPU 不同,Sparc64 CPU 没有不同的 32 位和 64 位减法指令:
如果你想从 0x12345678 中减去 1,结果是 0x12345677。如果您从 0xF00D12345678 中减去 1,则结果为 0xF00D12345677 因此,如果您仅使用寄存器的低 32 位,则 64 位减法与 32 位减法具有相同的效果-位减法。
因此 Sparc64 CPU 没有不同的 64 位和 32 位加法、减法、乘法、左移等指令。
当高 32 位影响低 32 位(例如右移)时,这些 CPU 对 32 位和 64 位操作有不同的指令。
然而,零标志 取决于subcc
操作的结果。
为了解决这个问题,Sparc64 CPU 将每个整数标志(零、溢出、进位、符号)都设置了两次:
如果寄存器的低 32 位为零,则设置 32 位零标志;如果寄存器的所有 64 位都为零,将设置 64 位零标志。
为了与现有的 32 位程序兼容,bne
指令将检查 32 位零标志,而不是 64 位零标志。
is systematically equal to 1410065408
1e10 = 0x200000000 + 1410065408 所以在 1410065408 步之后达到值 0x200000000,其低 32 位设置为 0,bne
将不再跳转。
然而,对于 1e11,您不应该得到 1410065408,而是 1215752192,因为 1e11 = 0x1700000000 + 1215752192。
bne
有一个名为 bpne
的新指令,最多有 4 个参数!
在最简单的变体(只有两个参数)中,指令应该(我已经 5 年没有使用 Sparc,所以我不确定)像这样工作:
bpne %icc, loop # Like bne (based on the 32-bit result)
bpne %xcc, loop # Like bne, but based on the 64-bit result
编辑
Error: Unknown opcode: 'bpne'
我刚刚尝试使用 GNU 汇编程序:
GNU 汇编程序将新指令命名为 bne
- 就像旧指令一样:
bne loop # Old variant
bne %icc, loop # New variant based on the 32-bit result
bne %xcc, loop # (New variant) Based on the 64-bit result
subcc %g1, 1, %g1
bpne %icc, loop
bpne %xcc, loop
nop
第一个 bpne
(或 bne
)没有意义:只要第一行跳转,第二行也会跳转。如果您不使用 .reorder
(但这是默认设置),您还需要在两个分支指令之间添加一个 nop
...
代码应该如下所示(假设您的汇编器也命名为 bpne
bne
):
subcc %g1, 1, %g1
bne %xcc, loop
nop
关于c - sparc64 上 sparc 汇编代码的 unsigned long long int 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49801769/
有没有办法将在 SPARC 上运行的 Solaris 设置为在小端模式下运行? 我一直在读到 v9 架构芯片是双端芯片,但默认情况下,系统以大端运行。如何切换到小端? 谢谢! 最佳答案 不,小端模式几
在过去的几个月里,我一直很好奇尝试为 SPARC 处理器(V8 或 V9)进行一些组装。我的问题是,我无法访问 SPARC 机器,有没有办法可以在我的 x86 机器上运行 SPARC 二进制文件?我看
我安装了 CentOS 7.6,然后在我的机器上安装了所有 QEMU。我有一个 SPARC 镜像,需要在 VM 中调出。我一直在使用 qemu-system-sparc . $ qemu-system
我很少有符合 SPARC V8 32 位架构的基准测试应用程序。我将它们用于 SPARC 32 位处理器的性能评估。然而,很少有应用程序在性能上达不到要求。我想测试 64 位 SPARC V9 架构(
我很少有符合 SPARC V8 32 位架构的基准测试应用程序。我将它们用于 SPARC 32 位处理器的性能评估。然而,很少有应用程序在性能上达不到要求。我想测试 64 位 SPARC V9 架构(
我正在学习 SPARC 程序集,我必须创建一个从寄存器中提取字段的脚本。该脚本接受 3 个值,初始编号、字段开始位置、字段长度。 它不能使用任何移位函数,但可以使用乘法和除法。 我目前患有呼吸道病毒,
我目前正在使用 Sparc 处理器系列的一些汇编代码,但我在处理一段代码时遇到了一些麻烦。我认为代码和输出解释了更多,但简而言之,这是我的问题: 当我调用函数时 println()我写入 %fp -
是否有与 x86 的单步模式等效的 SPARC?我想要的是在每条指令之后停止执行并将控制流移动到陷阱处理程序或类似的东西。 我考虑过在延迟执行槽中使用 ta 指令,但是当前一条指令是设置了 annul
我的 gcc 交叉编译器不支持Built-in functions for atomic memory access 。我如何使用 Sparc V8 架构的内联汇编来实现以下功能: long __sy
我希望我的程序让二进制文件中的每个函数在结束后都留有一些空间。这样一来,如果以后需要进行一些小的更改,则只需更改该功能,而额外的空间将作为解释小更改的空间。 -falign-function 可以完成
java -version 2>&1 |gawk 'NR==1{ gsub(/"/," "); print $3}' 这适用于 Linux 和 Solaris,它将返回该计算机中安装的 Java 版本
我想在我的 C 程序中编写一个什么都不做的非常简单的内联汇编例程否则然后将本地寄存器 %l0 - %l7 设置为不同的值。我尝试了以下直接的方法: asm volatile ( ".text\
我想在 Sparc 中进行一些“内联”汇编编程,我想知道如何通过寄存器传递来做到这一点。 最好用一个小例子来解释我的问题 int main() { int a = 5; int b = 6
我目前正在学习计算机科学,我的必修类(class)之一是“计算机组织和体系结构”——或者换句话说,是汇编语言的介绍。这个特定的类(class)使用 SPARC 语言,因为部门机器只与 SPARC 兼容
我正在开发一个跨平台应用程序,我希望为其提供 Solaris/SPARC 支持,但我无法再访问服务器。我在 VirtualBox 上有一个 OpenSolaris VM,但我不知道有任何可以用来编译和
我有安装了Solaris 10 SPARC的Sun服务器。 我已经使用tarball源代码成功安装了libevent和openssl。我正在尝试使用gnu gmake编译tor-0.2.5.16。我在
所以;在符合 v9 的 64 位 SPARC CPU 上,存在我知道的 cas 指令。这对单个字长值进行操作。 我还在网络上看到了对 casx 指令的引用 - 但我找不到更多关于它的信息。 我想知道
我正在尝试以正确的方式优化此代码。我所说的正确的意思是......我想有一种通用的方法来执行这些优化,如果其他人查看代码,他们将能够删除优化。 可读性的 C 代码示例... int a = 1; //
我想了解为什么使用此代码会出现总线错误。 int main() { int p=34; int *pp= (int *) ((char *)&p+1); cout<<*pp<<"\n"; return
我正在确定函数中的数字是否为零。如果它为零,我需要将一些字符串(如“Is Zero”)传递到我声明为 B 的变量中。我确定它是否为零的函数有效,但是当我尝试使用我的 SPARC 源代码将字符串传递到变
我是一名优秀的程序员,十分优秀!