GCC内联汇编器,混合寄存器大小(x86)
有谁知道我可以摆脱以下汇编警告?
代码是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, %0nt": "=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。 我确定编译器必须选择一个具有子寄存器的寄存器。
我知道我可以强制汇编代码使用特定的寄存器(及其子寄存器),但我想将寄存器分配工作留给编译器。
如果我没有记错,你可以使用%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
,而不是任何标准文档。
很久以前,但我可能需要这个为我自己的未来参考...
加上Chris的正确答案说,关键是在'%'和输出操作数的数字之间使用修饰符。 例如, "MOV %1, %0"
可能会变成"MOV %q1, %w0"
。
我在constraints.md中找不到任何内容,但/gcc/config/i386/i386.c在print_reg()
的源代码中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名称。
如果操作数[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));
请注意' %c1
'中的重要但稀疏的'c'。 这个宏相当于
ptr = (char *)ptr + bytes
但不使用通常的整数算术执行端口。
编辑以添加:
在x64中直接调用可能很困难,因为它需要另一个未记录的修饰符:' %P0
'(似乎是PIC)
#define ASM_CALL_FUNC(func)
__asm volatile("call %P0") :
/* no writes */ :
/* reads %0 */ "i" (func))
尽管只有大写字母“P”被ICC识别,但小写'p'修饰符在GCC中似乎也具有相同的功能。 更多细节可能在/gcc/config/i386/i386.c上。 搜索“'p'”。
当我在考虑这个问题时......你应该用克里斯第二种解决方案中的大写“Q”约束替换“q”约束:
int
test(int x)
{
int y;
asm ("xchg %b0, %h0" : "=Q" (y) : "0" (x));
return y;
}
在64位模式下,“q”和“Q”略有不同,您可以从中获得所有整数寄存器(ax,bx,cx,dx,si,di,sp,bp,r8-r15)的最低字节。 。 但是你只能得到四个原始386寄存器(ax,bx,cx,dx)的第二低字节(例如ah)。
链接地址: http://www.djcxy.com/p/86799.html