gcc内嵌汇编适配-Werror报错:expected ‘)’ before ‘:’ token排查
问题描述
现有如下C函数#1,通过内嵌汇编将返回值存入%eax寄存器,在gcc 7.5.0编译正常,但开启-Werror时触发「no return statement in function returning non-void」报错。为适配-Werror,修改为用栈变量ret_value存储返回值后,出现编译错误「error: expected ‘)’ before ‘:’ token」,尝试"=r"约束、显式声明clobber eax、添加eax到ret_val的mov指令均无效,请问问题出在哪里?
原函数#1代码
int check() { __asm__ __volatile__ ( <snip some activity that has a jump to not_supported> "movl $1, %eax \n\t" \ "jmp done \n\t" \ "not_supported:\n\t" \ "movl $0, %eax \n\t" \ "done:\n\t" ); }
修改后错误代码
int check() { int ret_value =0; __asm__ __volatile__ ( <snip some activity that has a jump to not_supported> "movl $1, %0 \n\t" : "=a"(ret_value) :: \ "jmp done \n\t" \ "not_supported:\n\t" \ "movl $0, %0 \n\t" : "=a"(ret_value) :: \ "done:\n\t" ); return ret_value; }
问题分析与解决
错误根源
你修改后的代码违反了GCC内嵌汇编的核心语法规则:一个__asm__块只能有一组约束定义(输出约束、输入约束、破坏寄存器列表),不能在汇编代码段中间插入:"=a"(ret_value) ::这类约束语句。你把约束拆分到了汇编代码的两个位置,导致编译器无法识别语法,触发「expected ‘)’ before ‘:’ token」错误。
正确修改方式
将所有汇编指令整合到一个字符串中,只在汇编代码块的末尾定义一次约束即可。因为使用"=a"约束时,GCC会自动把%0映射到%eax寄存器,完全符合你原代码的逻辑,同时通过栈变量ret_value承接返回值,满足-Werror对返回语句的要求。
正确代码示例:
int check() { int ret_value = 0; __asm__ __volatile__ ( <snip some activity that has a jump to not_supported> "movl $1, %0 \n\t" \ "jmp done \n\t" \ "not_supported:\n\t" \ "movl $0, %0 \n\t" \ "done:\n\t" : "=a"(ret_value) // 输出约束:ret_value对应%eax : // 无输入约束,留空 : // 无破坏寄存器需要声明,留空 ); return ret_value; }
额外说明
- 如果你的
<snip>部分涉及修改其他寄存器,需要在破坏列表(第三个冒号后)声明,比如如果修改了%ebx,就要写成: "ebx"; "=a"约束明确指定输出变量对应%eax,和你原代码手动写movl $1, %eax的逻辑完全一致,不需要额外的寄存器拷贝操作。
内容的提问来源于stack exchange,提问作者Jay D
相关产品推荐
相关产品推荐

