c-如何防止GCC在内联汇编时警告函数没有返回



我使用一点内联汇编将函数返回值加载到eax寄存器中。然而,如果函数被定义为这样的话,GCC会抱怨函数没有返回值:

char *trim(char *s);

这会生成以下2个警告:

control reaches end of non-void function [-Wreturn-type]
No return, in function returning non-void

因此使用了下面的弱别名。有没有更好的方法可以防止GCC抱怨_trim函数没有返回值?我试图禁用适当的编译器警告,但运气不太好。

这是我的代码:

// Trim all but digits from the string, return start of string.
void _trim(char *s) {
char *d;
// Save start of string for function return and set d=s.
asm volatile (
"mov %1, %0 n" // Set d = s.
"push %1"       // Save start of string for function return.
: "=r" (d) : "r" (s)
);
// Ignore everything but digits...
while (*s != '') {
if (isdigit(*s))
*d++ = *s;
s++;
}
*d = ''; // Terminate string.
asm volatile ( "pop %eax" ); // Retrieve beginning of string.
}
// Define weak alias to prevent gcc from squawking about no return value.
char *trim(char *) __attribute__ ((weak, alias ("_trim")));
#endif
int main(void) {
char line[80];
// ...
if (strlen(trim(line)) == 8)
// Do something...
}

您的内联asm完全无效。

  1. 不能在内联asm块中留下与输入时不同的堆栈指针。如果你这样做,编译器对堆栈的任何后续访问都将是错误的,所有的地狱都将崩溃。你不能只是"在以后的asm块中修复它",因为你无法保证编译器不会访问其间的堆栈。在您自己的示例中,您在两者之间调用isdigit,在不考虑函数调用ABI的情况下进行函数调用(堆栈必须在函数调用时对齐mod 16)。

  2. 将值加载到特定asm块中的eax(或ABI的返回值寄存器是什么)中不会从函数返回该值。它所做的只是对一个你告诉编译器你不会进行clobber的寄存器进行clobbert(你没有把它包括在asm块的clobber列表中),从而创造了另一个所有地狱都可能崩溃的原因。如果编译器在该寄存器中保存了一些重要的值(例如,ssp的堆栈金丝雀),并且在读回时得到了不同的值,那么任何事情都可能发生。即使忽略了这种破坏,也没有理由认为当函数返回时,您在eax中输入的值仍然存在,或者将作为函数的返回值。编译器可以在实际返回之前加载其他内容,或者进行转换(内联,或基于访问函数定义的各种过程间优化),以便调用方以其他方式获得返回值,而不是在对与ABI匹配的未知函数进行外部调用时使用的方式。

修复代码(最大限度地减少样式更改)的方法是:

char *trim(char *s) {
char *d, *d0;
d0 = d = s;
// Ignore everything but digits...
while (*s != '') {
if (isdigit(*s))
*d++ = *s;
s++;
}
*d = ''; // Terminate string.
return d0;
}

最新更新