简体   繁体   English

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

[英]Why a function pointer field in a LLVM IR struct is replaced by {}*?

I compiled the MUSL C library using Clang 3.3, and dumped the generated LLVM IR files. 我使用Clang 3.3编译了MUSL C库,并转储生成的LLVM IR文件。 I found that the FILE struct 我发现了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;
};

was compiled as 编译为

%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 }

in some IR files, but was compiled as 在一些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 }

in other source files. 在其他源文件中。 The only difference between these two IR structs is that a function pointer type field in the first form is replaced by {}* instead of its complete type. 这两个IR结构之间的唯一区别是第一种形式的函数指针类型字段被{} *替换而不是其完整类型。 Could anyone tell me why this happens and how to disable the {}* replacement? 谁能告诉我为什么会发生这种情况以及如何禁用{} *替换?

It's a known bug in Clang . 这是Clang中一个已知错误

I don't have any idea how to work-around it, though, other than building Clang yourself and applying the patch discussed at that bug (but be aware that patch was not committed for a reason). 我不知道如何解决它,除了自己构建Clang并应用该bug讨论的补丁 (但要注意补丁不是出于某种原因而提交)。

For a simpler example of what is happening here I can do the following: 有关此处发生的更简单的示例,我可以执行以下操作:

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

And the compiler doesn't know the type of thing but can use this in a header file because all it cares is the size of the operand (it's a pointer, so that will be pointer length bytes no matter what it's pointing to). 编译器不知道事物的类型,但可以在头文件中使用它,因为它所关心的只是操作数的大小(它是一个指针,因此无论它指向什么,它都将是指针长度字节)。

The same thing appears to be happening in the musl c library. 同样的事情似乎发生在musl c库中。 In some compilation units the entire type is defined and in others where it doesn't need access to the specific type the only thing which is known is that it is a pointer. 在某些编译单元中,定义了整个类型,在其他编译单元中,它不需要访问特定类型,唯一已知的是它是指针。

The fix is easy, rather than forward declaring the type include the header file with the definition of the full type. 修复很容易,而不是向前声明类型包括头文件和完整类型的定义。 DON'T DO THIS. 不要这样做。 You are increasing compile time by doing this and probably worse increasing the bloat of a final executable. 这样做会增加编译时间,并且可能会增加最终可执行文件的膨胀。 Exactly the thing which musl is written to avoid. 完全是为了避免而编写的musl。 If the compilation unit doesn't care about the full type then it won't know about the full type. 如果编译单元不关心完整类型,那么它将不知道完整类型。 But everything will still work correctly. 但一切仍然可以正常工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM