在以下c函数中
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”
);
}
返回值存储在eax
寄存器中
这在gcc(Ubuntu 7.5.0- 3ubuntu 1 ~18.04)7.5.0上编译得很好,但是在其他地方由于werror的执行而抱怨
error: no return statement in function returning non-void [-Werror=return-type]
因此,为了使gcc可以接受werror
,我添加了一个堆栈变量作为#1的返回值
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不允许编译,即使是非werror情况:
: error: expected ‘)’ before ‘:’ token
"movl $0, %0 \n\t" : "=r"(ret_value) :: \
它首先抱怨:在movl
指令中
我也试过用“=r”
寄存器操作数约束输出,但仍然不能编译。我也试过显式地将clobber寄存器指定为“eax”,但也没有帮助。
似乎gcc在jmp
之后抱怨ret_value
修改。
我尝试的另一件事是#1,另一个mov
从eax
到ret_val
,这在逻辑上对我来说没有意义。(我的意思是在done:
之后添加一个movl
指令,将%eax
的值移动到%0
,即ret_val
),这也没有编译。
我错过什么了吗?
1条答案
按热度按时间chhqkbe11#
@margaretBloom的建议很有帮助。我删除了多个输出操作数,只在最后保留了一个。这有助于编译,但反汇编后的输出如下所示:
这里编译器试图将堆栈变量的内容写入eax,从而覆盖了原来存储在eax中的真实的输出。
通过进一步的探索和错误修复,以下内容可以正常工作:
诀窍是在eax中记录结果,然后显式地将这些结果复制到返回值中沿着并进行适当的重写。另一件事是为指令提供寄存器操作数,而不是寄存器本身。