当前位置: 首页 > 知识库问答 >
问题:

gcc内联程序集-“add”的操作数类型不匹配,正在尝试创建无分支代码

能业
2023-03-14

我正在尝试做一些代码优化来消除分支,原始的c代码是

if( a < b ) 
   k = (k<<1) + 1;
else
   k = (k<<1)
mov a, %rax 
mov b, %rbx
mov k, %rcx
xor %rdx %rdx
shl 1, %rcx
cmp %rax, %rax
setb %rdx
add %rdx,%rcx
mov %rcx, k 
#define next(a, b, k)\
 __asm__("shl $0x1, %0; \
         xor %%rbx, %%rbx; \
         cmp %1, %2; \
         setb %%rbx; \
         addl  %%rbx,%0;":"+c"(k) :"g"(a),"g"(b))

当我编译下面的代码时,我得到了错误:

operand type mismatch for `add'
operand type mismatch for `setb'

我该怎么修好它?

共有1个答案

孙岳
2023-03-14

以下是您的代码中的错误:

  1. 错误:“cmp”的操作数类型不匹配--其中一个cmp的操作数必须是寄存器。您可能正在生成试图比较两个直接关系的代码。将第二个操作数的约束从“g”更改为“r”。(请参见GCC Manual-Extended Asm-Simple Constraints)
  2. 错误:“SETB”的操作数类型不匹配--SETB只接受8位操作数,即SETB%bl工作,而SETB%rbx不工作。
  3. C表达式t=(A 应转换为 cmp B,A;AT&T x86汇编程序语法中的setb t。要CMP的两个操作数的顺序不对。记住CMP的工作方式如下:

一旦您意识到前两个错误消息是由汇编程序生成的,那么调试它们的诀窍就是查看由gcc生成的汇编程序代码。尝试gcc$cflags-s t.c并将t.s中有问题的行与x86操作码引用进行比较。关注每条指令允许的操作数代码,您将很快看到问题所在。

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

static uint64_t next(uint64_t a, uint64_t b, uint64_t k)
{
    uint64_t tmp;
    __asm__("shl $0x1, %[k];"
        "xor %%rcx, %%rcx;"
        "cmp %[b], %[a];"
        "setb %%cl;"
        "addq %%rcx, %[k];"
        : /* outputs */ [k] "+g" (k), [tmp] "=&c" (tmp)
        : /* inputs  */ [a] "r" (a), [b] "g" (b)
        : /* clobbers */ "cc");
    return k;
}

int main()
{
    uint64_t t, t0, k;
    k = next(1, 2, 0);
    printf("%" PRId64 "\n", k);

    scanf("%" SCNd64 "%" SCNd64, &t, &t0);
    k = next(t, t0, k);
    printf("%" PRId64 "\n", k);

    return 0;
}

main()转换为:

<+0>:   push   %rbx
<+1>:   xor    %ebx,%ebx
<+3>:   mov    $0x4006c0,%edi
<+8>:   mov    $0x1,%bl
<+10>:  xor    %eax,%eax
<+12>:  sub    $0x10,%rsp
<+16>:  shl    %rax
<+19>:  xor    %rcx,%rcx
<+22>:  cmp    $0x2,%rbx
<+26>:  setb   %cl
<+29>:  add    %rcx,%rax
<+32>:  mov    %rax,%rbx
<+35>:  mov    %rax,%rsi
<+38>:  xor    %eax,%eax
<+40>:  callq  0x400470 <printf@plt>
<+45>:  lea    0x8(%rsp),%rdx
<+50>:  mov    %rsp,%rsi
<+53>:  mov    $0x4006c5,%edi
<+58>:  xor    %eax,%eax
<+60>:  callq  0x4004a0 <__isoc99_scanf@plt>
<+65>:  mov    (%rsp),%rax
<+69>:  mov    %rbx,%rsi
<+72>:  mov    $0x4006c0,%edi
<+77>:  shl    %rsi
<+80>:  xor    %rcx,%rcx
<+83>:  cmp    0x8(%rsp),%rax
<+88>:  setb   %cl
<+91>:  add    %rcx,%rsi
<+94>:  xor    %eax,%eax
<+96>:  callq  0x400470 <printf@plt>
<+101>: add    $0x10,%rsp
<+105>: xor    %eax,%eax
<+107>: pop    %rbx
<+108>: retq   

您可以看到next()在每次printf()调用之前被移动到RSI中的结果。

 类似资料:
  • 这里是一个虚拟的*z++=*x++**y++指令。请注意,x、y和z指针寄存器必须指定为输入/输出,因为asm会修改它们。 在第一个示例中,在输入操作数中列出和有什么意义?同一份文件指出: 特别是,如果不将输入操作数指定为输出操作数,就无法指定输入操作数被修改。

  • 我在函数中有以下代码: 现在我不知道为什么这不起作用。Gcc说:“错误:'asm'操作数有不可能的约束”我一直在学习Gcc内联汇编教程,我认为这是将参数从c代码带到内联汇编块的正确方法。 我还使用了为32位x86构建的gcc交叉编译器。

  • 我试着创建这个过程(作为一个系统),它需要两个参数,用户名和密码,并根据它们创建一个用户: 问题是,当我尝试执行此过程(作为一个系统)时,我遇到了以下错误: 错误报告:ORA-01031:权限不足ORA-06512:在第9行的“系统.过程\u创建\u客户端”处ORA-06512:在第1 01031行。00000-“权限不足”*原因:试图在没有适当权限的情况下更改当前用户名或密码。如果试图在没有必要

  • 从CSV文件中存在的数十亿中找到最大值的程序。 错误:java.io.ioException:映射项中的类型不匹配:应为org.apache.hadoop.io.text,已收到org.apache.hadoop.mapred.maptask$mapoutputbuffer.collect(maptask.java:1072)在org.apache.hadoop.mapred.maptask$ne

  • 尝试使用gcc:https://github.com/wolf9466/cpuminer-multi/blob/master/cryptonight_aesni.c编译此源文件时遇到此错误 “CRYPTONIGT_AESNI.c:162:4:错误:操作数约束不一致”

  • 错误:java.io.ioException:错误值类:类org.apache.hadoop.io.text不是类org.apache.hadoop.mapred.ifile$writer.append(ifile.java:194)在org.apache.hadoop.mapred.task$combineoutputCollector.collect(task.java:1350)在org.a