当前位置:  开发笔记 > 开发工具 > 正文

GCC内联汇编程序,混合寄存器大小(x86)

如何解决《GCC内联汇编程序,混合寄存器大小(x86)》经验,为你挑选了2个好方法。

有谁知道如何摆脱以下汇编警告?

代码是x86,32位:

int test (int x)
{
  int y;
  // do a bit-rotate by 8 on the lower word. leave upper word intact.
  asm ("rorw $8, %0\n\t": "=q"(y) :"0"(x));
  return y;
}

如果我编译它,我得到以下(非常有效)警告:

Warning: using `%ax' instead of `%eax' due to `w' suffix

我正在寻找的是告诉编译器/汇编器我想要访问%0的低16位子寄存器的方法.访问字节子寄存器(在本例中为AL和AH)也很好.

我已经选择了"q"修饰符,因此编译器被迫使用EAX,EBX,ECX或EDX.我已经确保编译器必须选择一个具有子寄存器的寄存器.

我知道我可以强制asm-code使用特定的寄存器(及其子寄存器),但我想将寄存器分配作业留给编译器.



1> Chris Jester..:

%w0如果我没记错的话,你可以使用.我也测试了它.:-)

int
test(int x)
{
    int y;
    asm ("rorw $8, %w0" : "=q" (y) : "0" (x));
    return y;
}

编辑:为了回应OP,是的,您也可以执行以下操作:

int
test(int x)
{
    int y;
    asm ("xchg %b0, %h0" : "=Q" (y) : "0" (x));
    return y;
}

目前,它所记录的唯一(我所知道的)是gcc/config/i386/i386.md,不在任何标准文档中.



2> Nathan Kurz..:

很久以前,但我可能需要这个以供将来参考...

除了克里斯的精细答案之外,关键是在'%'和输出操作数的数字之间使用修饰符.例如,"MOV %1, %0"可能会成为"MOV %q1, %w0".

我在constraints.md中找不到任何内容,但是/gcc/config/i386/i386.c在源代码中有这个可能有用的注释print_reg():

/* Print the name of register X to FILE based on its machine mode and number.
   If CODE is 'w', pretend the mode is HImode.
   If CODE is 'b', pretend the mode is QImode.
   If CODE is 'k', pretend the mode is SImode.
   If CODE is 'q', pretend the mode is DImode.
   If CODE is 'x', pretend the mode is V4SFmode.
   If CODE is 't', pretend the mode is V8SFmode.
   If CODE is 'h', pretend the reg is the 'high' byte register.
   If CODE is 'y', print "st(0)" instead of "st", if the reg is stack op.
   If CODE is 'd', duplicate the operand for AVX instruction.
 */

下面的评论ix86_print_operand()提供了一个例子:

b - 打印指示操作数的寄存器的QImode名称.

如果operands [0]为reg 0,则%b0将打印%al.

GCC Internals文档的输出模板下列出了一些更有用的选项:

'%cdigit'可用于替换作为常量值的操作数,而不使用通常表示立即操作数的语法.

'%ndigit'与'%cdigit'类似,只是在打印前取消常量的值.

'%adigit'可用于替换操作数,就好像它是一个内存引用一样,实际的操作数被视为地址.这在输出"加载地址"指令时可能很有用,因为这种指令的汇编语法通常要求您将操作数写为内存引用.

'%ldigit'用于将label_ref替换为跳转指令.

'%='输出一个对整个编译中的每条指令唯一的数字.这对于在生成多个汇编程序指令的单个模板中多次引用本地标签非常有用.

' %c2'结构允许使用偏移量正确格式化LEA指令:

#define ASM_LEA_ADD_BYTES(ptr, bytes)                            \
    __asm volatile("lea %c1(%0), %0" :                           \
                   /* reads/writes %0 */  "+r" (ptr) :           \
                   /* reads */ "i" (bytes));

注意''中关键但却稀疏记录的'c %c1'.这个宏相当于

ptr = (char *)ptr + bytes

但是没有使用通常的整数算术执行端口.

编辑添加:

在x64中进行直接调用可能很困难,因为它需要另一个未记录的修饰符:' %P0'(似乎是PIC)

#define ASM_CALL_FUNC(func)                                         \
    __asm volatile("call %P0") :                                    \
              /* no writes */ :                                     \
              /* reads %0 */ "i" (func))                           

小写'p'修饰符在GCC中似乎也起到相同的作用,尽管只有大写'P'被ICC认可.有关详细信息,请访问/gcc/config/i386/i386.c.搜索"'p'".


"完整"表现在也在源文件中,就像函数`ix86_print_operand()`之前的注释一样.它还提到(除其他外)`%p..` /`%P..`.
推荐阅读
路人甲
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有