使用sparc64上的sparc汇编代码的unsigned long long int问题

时间:2018-04-12 16:34:20

标签: c gcc assembly inline-assembly sparc

我在下面的C代码中遇到了一个问题,其中包括Sparc Assembly。代码在Debian 9.0 Sparc64上编译并运行。它执行简单的sumation并打印此总和的结果,该结果等于nLoop

问题是,对于大于1e + 9的初始迭代次数,末尾的最终总和系统地等于141006540​​8:我不明白为什么因为我明确unsigned long long int类型为{{ 1}}变量,因此sum可以在sum范围内。

例如,对于[0, +18,446,744,073,709,551,615],我希望nLoop = 1e+9等于sum

问题是来自包含无法处理64位变量(在输入或输出中)的Assembly Sparc代码吗?

1e+9

如何解决这个范围问题并允许将64位变量用于Sparc汇编代码?

此致

ps:我尝试用gcc -m64编译,问题仍然存在。

更新1:根据@zwol的要求,在使用以下内容生成的输出程序集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; }

gcc -O2 -m64 -S loop.c -o loop.s

更新2:

根据@Martin Rosenau的建议,我做了以下修改:

        .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

但在汇编时,我得到了:

loop:
        add %g2, 1, %g2
        subcc %g1, 1, %g1
        bpne %icc, loop
        bpne %xcc, loop
        nop
        mov %g2, %o1

有关此编译错误的任何线索?

2 个答案:

答案 0 :(得分:1)

subcc %%g1, 1, %%g1
bne loop

您的问题是bne说明:

与x86-64 CPU不同,Sparc64 CPU不具备32位和64位减法的不同指令:

如果要从0x12345678中减1,结果为0x12345677。如果从0xF00D 12345678 中减去1,则结果为0xF00D 12345677 ,因此如果仅使用寄存器的低32位,则64位减法与32具有相同的效果比特减法。

因此,Sparc64 CPU对64位和32位加法,减法,乘法,左移等没有不同的指令。

当高32位影响低32位(例如右移)时,这些CPU对32位和64位操作有不同的指令。

然而零标志取决于subcc操作的结果。

为了解决这个问题,Sparc64 CPU有两次整数标志(零,溢出,进位,符号):

如果寄存器的低32位为零,则 32位零标志将被置位;如果寄存器的所有64位都为零,则将设置 64位零标志

为了与现有的32位程序兼容,bne指令将检查32位零标志,而不是64位零标志。

  

系统地等于141006540​​8

1e10 = 0x200000000 + 141006540​​8所以在141006540​​8步之后,达到值0x200000000,其中低32位设置为0,bne不再跳转。

然而,对于1e11,您不应该得到141006540​​8但结果是1215752192因为1e11 = 0x1700000000 + 1215752192。

  

bne

有一条名为bpne的新指令,最多有4个参数!

在最简单的变体(只有两个参数)中,指令应该(我现在已经使用Sparc 5年了,所以我不确定)是这样工作的:

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

答案 1 :(得分:0)

尝试“bne%xcc,loop”,它应根据64位结果进行分支。