【问题标题】:Why a function pointer field in a LLVM IR struct is replaced by {}*?为什么 LLVM IR 结构中的函数指针字段被 {}* 替换?
【发布时间】:2013-09-10 23:58:29
【问题描述】:

我使用 Clang 3.3 编译了 MUSL C 库,并转储了生成的 LLVM IR 文件。我发现 FILE 结构

struct __FILE_s {
    unsigned flags;
    unsigned char *rpos, *rend;
    int (*close)(FILE *);
    unsigned char *wend, *wpos;
    unsigned char *mustbezero_1;
    unsigned char *wbase;
    size_t (*read)(FILE *, unsigned char *, size_t);
    size_t (*write)(FILE *, const unsigned char *, size_t);
    off_t (*seek)(FILE *, off_t, int);
    unsigned char *buf;
    size_t buf_size;
    FILE *prev, *next;
    int fd;
    int pipe_pid;
    long lockcount;
    short dummy3;
    signed char mode;
    signed char lbf;
    int lock;
    int waiters;
    void *cookie;
    off_t off;
    char *getln_buf;
    void *mustbezero_2;
    unsigned char *shend;
    off_t shlim, shcnt;
};

被编译为

%struct.__FILE_s = type { i32, i8*, i8*, 
i32 (%struct.__FILE_s*)*, i8*, i8*, i8*, i8*, 
i64 (%struct.__FILE_s*, i8*, i64)*, 
i64 (%struct.__FILE_s*, i8*, i64)*, 
i64 (%struct.__FILE_s*, i64, i32)*, 
i8*, i64, %struct.__FILE_s*, %struct.__FILE_s*, 
i32, i32, i64, i16, i8, i8, i32, i32, i8*, 
i64, i8*, i8*, i8*, i64, i64 }

在一些 IR 文件中,但被编译为

%struct.__FILE_s = type { i32, i8*, i8*, 
i32 (%struct.__FILE_s*)*, i8*, i8*, i8*, i8*, 
i64 (%struct.__FILE_s*, i8*, i64)*, 
{}*, 
i64 (%struct.__FILE_s*, i64, i32)*, 
i8*, i64, %struct.__FILE_s*, %struct.__FILE_s*, 
i32, i32, i64, i16, i8, i8, i32, i32, i8*, 
i64, i8*, i8*, i8*, i64, i64 }

在其他源文件中。这两个 IR 结构之间的唯一区别是第一种形式的函数指针类型字段被替换为 {}* 而不是其完整类型。谁能告诉我为什么会发生这种情况以及如何禁用 {}* 替换?

【问题讨论】:

    标签: c struct clang llvm llvm-ir


    【解决方案1】:

    我是a known bug in Clang

    不过,除了自己构建 Clang 并应用 the patch discussed at that bug 之外,我不知道如何解决它(但请注意,补丁未提交是有原因的)。

    【讨论】:

      【解决方案2】:

      对于这里发生的事情的更简单示例,我可以执行以下操作:

      struct thing;
      int do_work(struct thing *to_this);
      

      并且编译器不知道事物的类型,但可以在头文件中使用它,因为它只关心操作数的大小(它是一个指针,所以无论它指向什么,它都是指针长度字节)。

      musl c 库中似乎也在发生同样的事情。在某些编译单元中定义了整个类型,而在其他不需要访问特定类型的编译单元中,唯一已知的是它是一个指针。

      修复很简单,而不是前向声明类型包含带有完整类型定义的头文件。不要这样做。这样做会增加编译时间,而且可能会增加最终可执行文件的膨胀。这正是 musl 为了避免而写的。如果编译单元不关心完整类型,那么它就不会知道完整类型。但一切仍将正常工作。

      【讨论】:

      • 感谢您的回复。我认为问题更多的是 LLVM 实现特定的,因为即使包括完整的类型定义,仍然缺少一些结构字段(由 {}* 替换)。
      • 我没有遵循最后一段。但我也不相信这个答案是有道理的。为什么只有一个函数指针会受到影响,而不是所有其他也使用FILE *的函数指针会受到影响?
      • 你能解释一下你在最后一段中的意思吗?我不清楚您是说每个文件应该包含完整定义,还是不应该
      猜你喜欢
      • 1970-01-01
      • 2017-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多