有谁知道如何摆脱以下汇编警告?
代码是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使用特定的寄存器(及其子寄存器),但我想将寄存器分配作业留给编译器.
%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
,不在任何标准文档中.
很久以前,但我可能需要这个以供将来参考...
除了克里斯的精细答案之外,关键是在'%'和输出操作数的数字之间使用修饰符.例如,"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'".