为什么LLVM IR结构中的函数指针字段被{} *替换?

时间:2013-09-10 23:58:29

标签: c struct clang llvm llvm-ir

我使用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结构之间的唯一区别是第一种形式的函数指针类型字段被{} *替换而不是其完整类型。谁能告诉我为什么会发生这种情况以及如何禁用{} *替换?

2 个答案:

答案 0 :(得分:2)

这是a known bug in Clang

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

答案 1 :(得分:0)

有关此处发生的事情的简单示例,我可以执行以下操作:

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

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

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

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

相关问题