很久以前,但我可能需要这个作为我自己未来的参考......
加上克里斯的好回答说,关键是在“%”和输出操作数的数量之间使用修饰符。例如,"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 名称。
如果操作数 [0] 为 reg 0,则 %b0 将打印 %al。
GCC 内部文档的输出模板下列出了一些更有用的选项:
'%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 中的作用似乎也相同,尽管 ICC 只识别大写的“P”。/gcc/config/i386/i386.c可能提供更多详细信息。搜索“'p'”。