添加ecx到内联asm破坏列表导致编译错误的原因排查
GCC内联汇编约束冲突问题解答
问题场景
我尝试编译这段C代码:
unsigned long func(int priority) { unsigned long a; if (a) __asm__ __volatile__("rep ; stosl" : /* no outputs */ \ :"a" (0),"c" (1024),"D" (page) :"ecx"); return a; }
编译时报错:
a.c:6:3: error: ‘asm’ operand has impossible constraints __asm__ __volatile__("rep ; stosl" ^~~~~~~
删除破坏列表中的"ecx"条目后,代码可正常编译:
unsigned long func(int priority) { unsigned long a; if (a) __asm__ __volatile__("rep ; stosl" : /* no outputs */ \ :"a" (0),"c" (1024),"D" (page) ); return a; }
内联汇编明明支持asm("....":output:input:Clobbers)语法,为什么我的代码会报错?(环境:GCC 7.5.0,x86-64平台)
错误原因
核心问题是输入约束和破坏列表的寄存器冲突:
- 你用
"c" (1024)作为输入约束,这是告诉GCC把数值1024加载到ecx寄存器,作为汇编代码的输入参数。 - 同时又在破坏列表里声明
"ecx",相当于告诉GCC这段汇编会修改ecx,编译器无需保留该寄存器的原值。
GCC的内联汇编规则明确禁止这种操作:一个寄存器不能同时被标记为输入约束和破坏项。因为输入约束要求编译器保证该寄存器的初始值有效,而破坏列表则表示寄存器值会被修改,两者逻辑矛盾,因此编译器直接抛出"impossible constraints"错误。
另外补充:rep stosl指令本身确实会自动递减ecx直到为0,但由于你已经通过"c"约束将ecx作为输入寄存器,GCC已经知晓该指令会修改ecx的行为,所以完全不需要额外在破坏列表里声明它。
内容的提问来源于stack exchange,提问作者Kid
相关产品推荐
相关产品推荐

