c - 从 C 库调用符号时忽略返回值是否安全

标签 c llvm abi

我一直在摆弄 LLVM 并编写了一个简单的编译器。它使用 libc 作为标准库。当然,我必须以某种方式在我的 IR 中声明函数。

我注意到以下似乎有效:

declare void @puts(i8*)

在 C 中,函数定义如下:

int puts(const char *s);

应该是这样

declare i32 @puts(i8*)

这是一个非常简单的案例,但我确信我在过程中的某个地方会在声明这些函数时出错。例如,在阅读联机帮助页之前,我并不知道 puts 返回了一个 int。

这些错误有多严重?它会弄乱堆栈还是 LLVM 会以某种方式处理它?此类错误的安全隐患是什么?

注意:我无法用 putsvoid 声明产生任何错误。

最佳答案

这个问题的答案取决于您的 C 编译器的 ABI 使用的调用约定。在 x86 和 x86-64 上大多数 C 编译器使用的约定中,返回值在寄存器中传递。将 int 返回函数错误声明为 void 将导致返回寄存器的值被忽略(如果您不使用它,无论如何都会被忽略)。这不会造成任何伤害,因为调用者无论如何都要负责保存 eax 寄存器。

例如下面的代码:

void callee(int, int, int);

void caller(void)
{
  callee(1, 2, 3);
}

...如果您声明 callee 返回 int 而不是 void,将被编译成完全相同的程序集。

这适用于“小”返回类型,即由整数、 double float 或 64 位整数(x86 在两个整数寄存器中返回)组成的类型。大型返回类型的处理方式不同 - 如果您将 callee 的声明更改为类似以下内容:

struct { char x[100]; } callee(int, int, int);

...调用代码将发生巨大变化,尽管传入的类型没有改变。返回结构现在将分配在调用者的堆栈上,其地址将作为隐藏的第一个参数传递给被调用者(这是在 x86 上,x86-64 上的情况略有不同),预计将写入返回值到那个区域。

换句话说,只要您了解调用约定,并且注意不要错误声明按值返回大类型的函数(据我所知,标准 C 和 POSIX 库中不存在),错误的声明将起作用。

关于c - 从 C 库调用符号时忽略返回值是否安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35995509/

相关文章:

android - 如何在 NDK r17+ 中支持具有 MIPS 架构的设备?

windows - "ABI-volatile"寄存器被视为跨函数调用的非 volatile

objective-c - 使用 Xcode 项目 Objective C 加载 C 共享库

C 编译器预处理器输出

python /赛通 : Using SciPy with Cython

c - 在 GTK C 中填充模型后在组合框中获取空间

cmake - 如何仅在cmake中匹配主要版本

c - LLVM 作为不同语言的基础编译器

c++ - 使用 clang 从 C++ 编译到 LLVM IR 时指定多个文件

c++ - 知道哪个编译器用 C++ 生成特定的二进制文件至关重要吗?